mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
Merge tag 'for-linus-3.4' of git://git.infradead.org/mtd-2.6
Pull MTD changes from David Woodhouse: - Artem's cleanup of the MTD API continues apace. - Fixes and improvements for ST FSMC and SuperH FLCTL NAND, amongst others. - More work on DiskOnChip G3, new driver for DiskOnChip G4. - Clean up debug/warning printks in JFFS2 to use pr_<level>. Fix up various trivial conflicts, largely due to changes in calling conventions for things like dmaengine_prep_slave_sg() (new inline wrapper to hide new parameter, clashing with rewrite of previously last parameter that used to be an 'append' flag, and is now a bitmap of 'unsigned long flags'). (Also some header file fallout - like so many merges this merge window - and silly conflicts with sparse fixes) * tag 'for-linus-3.4' of git://git.infradead.org/mtd-2.6: (120 commits) mtd: docg3 add protection against concurrency mtd: docg3 refactor cascade floors structure mtd: docg3 increase write/erase timeout mtd: docg3 fix inbound calculations mtd: nand: gpmi: fix function annotations mtd: phram: fix section mismatch for phram_setup mtd: unify initialization of erase_info->fail_addr mtd: support ONFI multi lun NAND mtd: sm_ftl: fix typo in major number. mtd: add device-tree support to spear_smi mtd: spear_smi: Remove default partition information from driver mtd: Add device-tree support to fsmc_nand mtd: fix section mismatch for doc_probe_device mtd: nand/fsmc: Remove sparse warnings and errors mtd: nand/fsmc: Add DMA support mtd: nand/fsmc: Access the NAND device word by word whenever possible mtd: nand/fsmc: Use dev_err to report error scenario mtd: nand/fsmc: Use devm routines mtd: nand/fsmc: Modify fsmc driver to accept nand timing parameters via platform mtd: fsmc_nand: add pm callbacks to support hibernation ...
This commit is contained in:
33
Documentation/devicetree/bindings/mtd/fsmc-nand.txt
Normal file
33
Documentation/devicetree/bindings/mtd/fsmc-nand.txt
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
* FSMC NAND
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : "st,spear600-fsmc-nand"
|
||||||
|
- reg : Address range of the mtd chip
|
||||||
|
- reg-names: Should contain the reg names "fsmc_regs" and "nand_data"
|
||||||
|
- st,ale-off : Chip specific offset to ALE
|
||||||
|
- st,cle-off : Chip specific offset to CLE
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- bank-width : Width (in bytes) of the device. If not present, the width
|
||||||
|
defaults to 1 byte
|
||||||
|
- nand-skip-bbtscan: Indicates the the BBT scanning should be skipped
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
fsmc: flash@d1800000 {
|
||||||
|
compatible = "st,spear600-fsmc-nand";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
reg = <0xd1800000 0x1000 /* FSMC Register */
|
||||||
|
0xd2000000 0x4000>; /* NAND Base */
|
||||||
|
reg-names = "fsmc_regs", "nand_data";
|
||||||
|
st,ale-off = <0x20000>;
|
||||||
|
st,cle-off = <0x10000>;
|
||||||
|
|
||||||
|
bank-width = <1>;
|
||||||
|
nand-skip-bbtscan;
|
||||||
|
|
||||||
|
partition@0 {
|
||||||
|
...
|
||||||
|
};
|
||||||
|
};
|
||||||
31
Documentation/devicetree/bindings/mtd/spear_smi.txt
Normal file
31
Documentation/devicetree/bindings/mtd/spear_smi.txt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
* SPEAr SMI
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : "st,spear600-smi"
|
||||||
|
- reg : Address range of the mtd chip
|
||||||
|
- #address-cells, #size-cells : Must be present if the device has sub-nodes
|
||||||
|
representing partitions.
|
||||||
|
- interrupt-parent: Should be the phandle for the interrupt controller
|
||||||
|
that services interrupts for this device
|
||||||
|
- interrupts: Should contain the STMMAC interrupts
|
||||||
|
- clock-rate : Functional clock rate of SMI in Hz
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- st,smi-fast-mode : Flash supports read in fast mode
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
smi: flash@fc000000 {
|
||||||
|
compatible = "st,spear600-smi";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
reg = <0xfc000000 0x1000>;
|
||||||
|
interrupt-parent = <&vic1>;
|
||||||
|
interrupts = <12>;
|
||||||
|
clock-rate = <50000000>; /* 50MHz */
|
||||||
|
|
||||||
|
flash@f8000000 {
|
||||||
|
st,smi-fast-mode;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -17,20 +17,12 @@
|
|||||||
|
|
||||||
void omap1_set_vpp(struct platform_device *pdev, int enable)
|
void omap1_set_vpp(struct platform_device *pdev, int enable)
|
||||||
{
|
{
|
||||||
static int count;
|
|
||||||
u32 l;
|
u32 l;
|
||||||
|
|
||||||
if (enable) {
|
l = omap_readl(EMIFS_CONFIG);
|
||||||
if (count++ == 0) {
|
if (enable)
|
||||||
l = omap_readl(EMIFS_CONFIG);
|
l |= OMAP_EMIFS_CONFIG_WP;
|
||||||
l |= OMAP_EMIFS_CONFIG_WP;
|
else
|
||||||
omap_writel(l, EMIFS_CONFIG);
|
l &= ~OMAP_EMIFS_CONFIG_WP;
|
||||||
}
|
omap_writel(l, EMIFS_CONFIG);
|
||||||
} else {
|
|
||||||
if (count && (--count == 0)) {
|
|
||||||
l = omap_readl(EMIFS_CONFIG);
|
|
||||||
l &= ~OMAP_EMIFS_CONFIG_WP;
|
|
||||||
omap_writel(l, EMIFS_CONFIG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,9 +35,7 @@
|
|||||||
static void simtec_nor_vpp(struct platform_device *pdev, int vpp)
|
static void simtec_nor_vpp(struct platform_device *pdev, int vpp)
|
||||||
{
|
{
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
local_irq_save(flags);
|
|
||||||
val = __raw_readb(BAST_VA_CTRL3);
|
val = __raw_readb(BAST_VA_CTRL3);
|
||||||
|
|
||||||
printk(KERN_DEBUG "%s(%d)\n", __func__, vpp);
|
printk(KERN_DEBUG "%s(%d)\n", __func__, vpp);
|
||||||
@@ -48,7 +46,6 @@ static void simtec_nor_vpp(struct platform_device *pdev, int vpp)
|
|||||||
val &= ~BAST_CPLD_CTRL3_ROMWEN;
|
val &= ~BAST_CPLD_CTRL3_ROMWEN;
|
||||||
|
|
||||||
__raw_writeb(val, BAST_VA_CTRL3);
|
__raw_writeb(val, BAST_VA_CTRL3);
|
||||||
local_irq_restore(flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct physmap_flash_data simtec_nor_pdata = {
|
static struct physmap_flash_data simtec_nor_pdata = {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <linux/mtd/mtd.h>
|
#include <linux/mtd/mtd.h>
|
||||||
#include <linux/mtd/partitions.h>
|
#include <linux/mtd/partitions.h>
|
||||||
#include <linux/mtd/physmap.h>
|
#include <linux/mtd/physmap.h>
|
||||||
|
#include <linux/mtd/sh_flctl.h>
|
||||||
#include <linux/pm_clock.h>
|
#include <linux/pm_clock.h>
|
||||||
#include <linux/smsc911x.h>
|
#include <linux/smsc911x.h>
|
||||||
#include <linux/sh_intc.h>
|
#include <linux/sh_intc.h>
|
||||||
@@ -956,6 +957,50 @@ static struct platform_device fsi_ak4643_device = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* FLCTL */
|
||||||
|
static struct mtd_partition nand_partition_info[] = {
|
||||||
|
{
|
||||||
|
.name = "system",
|
||||||
|
.offset = 0,
|
||||||
|
.size = 128 * 1024 * 1024,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "userdata",
|
||||||
|
.offset = MTDPART_OFS_APPEND,
|
||||||
|
.size = 256 * 1024 * 1024,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "cache",
|
||||||
|
.offset = MTDPART_OFS_APPEND,
|
||||||
|
.size = 128 * 1024 * 1024,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource nand_flash_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = 0xe6a30000,
|
||||||
|
.end = 0xe6a3009b,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sh_flctl_platform_data nand_flash_data = {
|
||||||
|
.parts = nand_partition_info,
|
||||||
|
.nr_parts = ARRAY_SIZE(nand_partition_info),
|
||||||
|
.flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET
|
||||||
|
| SHBUSSEL | SEL_16BIT | SNAND_E,
|
||||||
|
.use_holden = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device nand_flash_device = {
|
||||||
|
.name = "sh_flctl",
|
||||||
|
.resource = nand_flash_resources,
|
||||||
|
.num_resources = ARRAY_SIZE(nand_flash_resources),
|
||||||
|
.dev = {
|
||||||
|
.platform_data = &nand_flash_data,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The card detect pin of the top SD/MMC slot (CN7) is active low and is
|
* The card detect pin of the top SD/MMC slot (CN7) is active low and is
|
||||||
* connected to GPIO A22 of SH7372 (GPIO_PORT41).
|
* connected to GPIO A22 of SH7372 (GPIO_PORT41).
|
||||||
@@ -1259,6 +1304,7 @@ static struct platform_device *mackerel_devices[] __initdata = {
|
|||||||
&fsi_device,
|
&fsi_device,
|
||||||
&fsi_ak4643_device,
|
&fsi_ak4643_device,
|
||||||
&fsi_hdmi_device,
|
&fsi_hdmi_device,
|
||||||
|
&nand_flash_device,
|
||||||
&sdhi0_device,
|
&sdhi0_device,
|
||||||
#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
|
#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
|
||||||
&sdhi1_device,
|
&sdhi1_device,
|
||||||
@@ -1488,6 +1534,30 @@ static void __init mackerel_init(void)
|
|||||||
gpio_request(GPIO_FN_MMCCMD0, NULL);
|
gpio_request(GPIO_FN_MMCCMD0, NULL);
|
||||||
gpio_request(GPIO_FN_MMCCLK0, NULL);
|
gpio_request(GPIO_FN_MMCCLK0, NULL);
|
||||||
|
|
||||||
|
/* FLCTL */
|
||||||
|
gpio_request(GPIO_FN_D0_NAF0, NULL);
|
||||||
|
gpio_request(GPIO_FN_D1_NAF1, NULL);
|
||||||
|
gpio_request(GPIO_FN_D2_NAF2, NULL);
|
||||||
|
gpio_request(GPIO_FN_D3_NAF3, NULL);
|
||||||
|
gpio_request(GPIO_FN_D4_NAF4, NULL);
|
||||||
|
gpio_request(GPIO_FN_D5_NAF5, NULL);
|
||||||
|
gpio_request(GPIO_FN_D6_NAF6, NULL);
|
||||||
|
gpio_request(GPIO_FN_D7_NAF7, NULL);
|
||||||
|
gpio_request(GPIO_FN_D8_NAF8, NULL);
|
||||||
|
gpio_request(GPIO_FN_D9_NAF9, NULL);
|
||||||
|
gpio_request(GPIO_FN_D10_NAF10, NULL);
|
||||||
|
gpio_request(GPIO_FN_D11_NAF11, NULL);
|
||||||
|
gpio_request(GPIO_FN_D12_NAF12, NULL);
|
||||||
|
gpio_request(GPIO_FN_D13_NAF13, NULL);
|
||||||
|
gpio_request(GPIO_FN_D14_NAF14, NULL);
|
||||||
|
gpio_request(GPIO_FN_D15_NAF15, NULL);
|
||||||
|
gpio_request(GPIO_FN_FCE0, NULL);
|
||||||
|
gpio_request(GPIO_FN_WE0_FWE, NULL);
|
||||||
|
gpio_request(GPIO_FN_FRB, NULL);
|
||||||
|
gpio_request(GPIO_FN_A4_FOE, NULL);
|
||||||
|
gpio_request(GPIO_FN_A5_FCDE, NULL);
|
||||||
|
gpio_request(GPIO_FN_RD_FSC, NULL);
|
||||||
|
|
||||||
/* enable GPS module (GT-720F) */
|
/* enable GPS module (GT-720F) */
|
||||||
gpio_request(GPIO_FN_SCIFA2_TXD1, NULL);
|
gpio_request(GPIO_FN_SCIFA2_TXD1, NULL);
|
||||||
gpio_request(GPIO_FN_SCIFA2_RXD1, NULL);
|
gpio_request(GPIO_FN_SCIFA2_RXD1, NULL);
|
||||||
@@ -1532,6 +1602,7 @@ static void __init mackerel_init(void)
|
|||||||
sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device);
|
sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device);
|
||||||
sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs0_device);
|
sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs0_device);
|
||||||
sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs1_device);
|
sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs1_device);
|
||||||
|
sh7372_add_device_to_domain(&sh7372_a3sp, &nand_flash_device);
|
||||||
sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device);
|
sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device);
|
||||||
sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device);
|
sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device);
|
||||||
#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
|
#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
|
||||||
|
|||||||
@@ -511,7 +511,7 @@ enum { MSTP001, MSTP000,
|
|||||||
MSTP223,
|
MSTP223,
|
||||||
MSTP218, MSTP217, MSTP216, MSTP214, MSTP208, MSTP207,
|
MSTP218, MSTP217, MSTP216, MSTP214, MSTP208, MSTP207,
|
||||||
MSTP206, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
|
MSTP206, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
|
||||||
MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
|
MSTP328, MSTP323, MSTP322, MSTP315, MSTP314, MSTP313, MSTP312,
|
||||||
MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP407, MSTP406,
|
MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP407, MSTP406,
|
||||||
MSTP405, MSTP404, MSTP403, MSTP400,
|
MSTP405, MSTP404, MSTP403, MSTP400,
|
||||||
MSTP_NR };
|
MSTP_NR };
|
||||||
@@ -553,6 +553,7 @@ static struct clk mstp_clks[MSTP_NR] = {
|
|||||||
[MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSI2 */
|
[MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSI2 */
|
||||||
[MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
|
[MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
|
||||||
[MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */
|
[MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */
|
||||||
|
[MSTP315] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 15, 0), /* FLCTL*/
|
||||||
[MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */
|
[MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */
|
||||||
[MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
|
[MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
|
||||||
[MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMC */
|
[MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMC */
|
||||||
@@ -653,6 +654,7 @@ static struct clk_lookup lookups[] = {
|
|||||||
CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */
|
CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */
|
||||||
CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USB0 */
|
CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USB0 */
|
||||||
CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP322]), /* USB0 */
|
CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP322]), /* USB0 */
|
||||||
|
CLKDEV_DEV_ID("sh_flctl.0", &mstp_clks[MSTP315]), /* FLCTL */
|
||||||
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
|
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
|
||||||
CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
|
CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
|
||||||
CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
|
CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
|
||||||
|
|||||||
@@ -1544,6 +1544,8 @@ static struct fsmc_nand_platform_data nand_platform_data = {
|
|||||||
.nr_partitions = ARRAY_SIZE(u300_partitions),
|
.nr_partitions = ARRAY_SIZE(u300_partitions),
|
||||||
.options = NAND_SKIP_BBTSCAN,
|
.options = NAND_SKIP_BBTSCAN,
|
||||||
.width = FSMC_NAND_BW8,
|
.width = FSMC_NAND_BW8,
|
||||||
|
.ale_off = PLAT_NAND_ALE,
|
||||||
|
.cle_off = PLAT_NAND_CLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_device nand_device = {
|
static struct platform_device nand_device = {
|
||||||
|
|||||||
@@ -24,6 +24,11 @@
|
|||||||
/* NFIF */
|
/* NFIF */
|
||||||
#define U300_NAND_IF_PHYS_BASE 0x9f800000
|
#define U300_NAND_IF_PHYS_BASE 0x9f800000
|
||||||
|
|
||||||
|
/* ALE, CLE offset for FSMC NAND */
|
||||||
|
#define PLAT_NAND_CLE (1 << 16)
|
||||||
|
#define PLAT_NAND_ALE (1 << 17)
|
||||||
|
|
||||||
|
|
||||||
/* AHB Peripherals */
|
/* AHB Peripherals */
|
||||||
#define U300_AHB_PER_PHYS_BASE 0xa0000000
|
#define U300_AHB_PER_PHYS_BASE 0xa0000000
|
||||||
#define U300_AHB_PER_VIRT_BASE 0xff010000
|
#define U300_AHB_PER_VIRT_BASE 0xff010000
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ static int __init flash_init(void)
|
|||||||
if (mymtd) {
|
if (mymtd) {
|
||||||
mymtd->owner = THIS_MODULE;
|
mymtd->owner = THIS_MODULE;
|
||||||
mtd_device_parse_register(mymtd, part_probe_types,
|
mtd_device_parse_register(mymtd, part_probe_types,
|
||||||
0, NULL, 0);
|
NULL, NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
pr_err("Failed to register MTD device for flash\n");
|
pr_err("Failed to register MTD device for flash\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,10 @@
|
|||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/dmaengine.h>
|
#include <linux/dmaengine.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/fsl/mxs-dma.h>
|
||||||
|
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
#include <mach/mxs.h>
|
#include <mach/mxs.h>
|
||||||
#include <mach/dma.h>
|
|
||||||
#include <mach/common.h>
|
#include <mach/common.h>
|
||||||
|
|
||||||
#include "dmaengine.h"
|
#include "dmaengine.h"
|
||||||
@@ -337,10 +337,32 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
|
|||||||
clk_disable_unprepare(mxs_dma->clk);
|
clk_disable_unprepare(mxs_dma->clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How to use the flags for ->device_prep_slave_sg() :
|
||||||
|
* [1] If there is only one DMA command in the DMA chain, the code should be:
|
||||||
|
* ......
|
||||||
|
* ->device_prep_slave_sg(DMA_CTRL_ACK);
|
||||||
|
* ......
|
||||||
|
* [2] If there are two DMA commands in the DMA chain, the code should be
|
||||||
|
* ......
|
||||||
|
* ->device_prep_slave_sg(0);
|
||||||
|
* ......
|
||||||
|
* ->device_prep_slave_sg(DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
|
* ......
|
||||||
|
* [3] If there are more than two DMA commands in the DMA chain, the code
|
||||||
|
* should be:
|
||||||
|
* ......
|
||||||
|
* ->device_prep_slave_sg(0); // First
|
||||||
|
* ......
|
||||||
|
* ->device_prep_slave_sg(DMA_PREP_INTERRUPT [| DMA_CTRL_ACK]);
|
||||||
|
* ......
|
||||||
|
* ->device_prep_slave_sg(DMA_PREP_INTERRUPT | DMA_CTRL_ACK); // Last
|
||||||
|
* ......
|
||||||
|
*/
|
||||||
static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
|
static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
|
||||||
struct dma_chan *chan, struct scatterlist *sgl,
|
struct dma_chan *chan, struct scatterlist *sgl,
|
||||||
unsigned int sg_len, enum dma_transfer_direction direction,
|
unsigned int sg_len, enum dma_transfer_direction direction,
|
||||||
unsigned long append, void *context)
|
unsigned long flags, void *context)
|
||||||
{
|
{
|
||||||
struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
|
struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
|
||||||
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
|
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
|
||||||
@@ -348,6 +370,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
|
|||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
int i, j;
|
int i, j;
|
||||||
u32 *pio;
|
u32 *pio;
|
||||||
|
bool append = flags & DMA_PREP_INTERRUPT;
|
||||||
int idx = append ? mxs_chan->desc_count : 0;
|
int idx = append ? mxs_chan->desc_count : 0;
|
||||||
|
|
||||||
if (mxs_chan->status == DMA_IN_PROGRESS && !append)
|
if (mxs_chan->status == DMA_IN_PROGRESS && !append)
|
||||||
@@ -374,7 +397,6 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
|
|||||||
ccw->bits |= CCW_CHAIN;
|
ccw->bits |= CCW_CHAIN;
|
||||||
ccw->bits &= ~CCW_IRQ;
|
ccw->bits &= ~CCW_IRQ;
|
||||||
ccw->bits &= ~CCW_DEC_SEM;
|
ccw->bits &= ~CCW_DEC_SEM;
|
||||||
ccw->bits &= ~CCW_WAIT4END;
|
|
||||||
} else {
|
} else {
|
||||||
idx = 0;
|
idx = 0;
|
||||||
}
|
}
|
||||||
@@ -389,7 +411,8 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
|
|||||||
ccw->bits = 0;
|
ccw->bits = 0;
|
||||||
ccw->bits |= CCW_IRQ;
|
ccw->bits |= CCW_IRQ;
|
||||||
ccw->bits |= CCW_DEC_SEM;
|
ccw->bits |= CCW_DEC_SEM;
|
||||||
ccw->bits |= CCW_WAIT4END;
|
if (flags & DMA_CTRL_ACK)
|
||||||
|
ccw->bits |= CCW_WAIT4END;
|
||||||
ccw->bits |= CCW_HALT_ON_TERM;
|
ccw->bits |= CCW_HALT_ON_TERM;
|
||||||
ccw->bits |= CCW_TERM_FLUSH;
|
ccw->bits |= CCW_TERM_FLUSH;
|
||||||
ccw->bits |= BF_CCW(sg_len, PIO_NUM);
|
ccw->bits |= BF_CCW(sg_len, PIO_NUM);
|
||||||
@@ -420,7 +443,8 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
|
|||||||
ccw->bits &= ~CCW_CHAIN;
|
ccw->bits &= ~CCW_CHAIN;
|
||||||
ccw->bits |= CCW_IRQ;
|
ccw->bits |= CCW_IRQ;
|
||||||
ccw->bits |= CCW_DEC_SEM;
|
ccw->bits |= CCW_DEC_SEM;
|
||||||
ccw->bits |= CCW_WAIT4END;
|
if (flags & DMA_CTRL_ACK)
|
||||||
|
ccw->bits |= CCW_WAIT4END;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,10 +38,10 @@
|
|||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/fsl/mxs-dma.h>
|
||||||
|
|
||||||
#include <mach/mxs.h>
|
#include <mach/mxs.h>
|
||||||
#include <mach/common.h>
|
#include <mach/common.h>
|
||||||
#include <mach/dma.h>
|
|
||||||
#include <mach/mmc.h>
|
#include <mach/mmc.h>
|
||||||
|
|
||||||
#define DRIVER_NAME "mxs-mmc"
|
#define DRIVER_NAME "mxs-mmc"
|
||||||
@@ -305,7 +305,7 @@ static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
|
static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
|
||||||
struct mxs_mmc_host *host, unsigned int append)
|
struct mxs_mmc_host *host, unsigned long flags)
|
||||||
{
|
{
|
||||||
struct dma_async_tx_descriptor *desc;
|
struct dma_async_tx_descriptor *desc;
|
||||||
struct mmc_data *data = host->data;
|
struct mmc_data *data = host->data;
|
||||||
@@ -325,7 +325,7 @@ static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
|
|||||||
}
|
}
|
||||||
|
|
||||||
desc = dmaengine_prep_slave_sg(host->dmach,
|
desc = dmaengine_prep_slave_sg(host->dmach,
|
||||||
sgl, sg_len, host->slave_dirn, append);
|
sgl, sg_len, host->slave_dirn, flags);
|
||||||
if (desc) {
|
if (desc) {
|
||||||
desc->callback = mxs_mmc_dma_irq_callback;
|
desc->callback = mxs_mmc_dma_irq_callback;
|
||||||
desc->callback_param = host;
|
desc->callback_param = host;
|
||||||
@@ -358,7 +358,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host)
|
|||||||
host->ssp_pio_words[2] = cmd1;
|
host->ssp_pio_words[2] = cmd1;
|
||||||
host->dma_dir = DMA_NONE;
|
host->dma_dir = DMA_NONE;
|
||||||
host->slave_dirn = DMA_TRANS_NONE;
|
host->slave_dirn = DMA_TRANS_NONE;
|
||||||
desc = mxs_mmc_prep_dma(host, 0);
|
desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK);
|
||||||
if (!desc)
|
if (!desc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -398,7 +398,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host)
|
|||||||
host->ssp_pio_words[2] = cmd1;
|
host->ssp_pio_words[2] = cmd1;
|
||||||
host->dma_dir = DMA_NONE;
|
host->dma_dir = DMA_NONE;
|
||||||
host->slave_dirn = DMA_TRANS_NONE;
|
host->slave_dirn = DMA_TRANS_NONE;
|
||||||
desc = mxs_mmc_prep_dma(host, 0);
|
desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK);
|
||||||
if (!desc)
|
if (!desc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -526,7 +526,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
|
|||||||
host->data = data;
|
host->data = data;
|
||||||
host->dma_dir = dma_data_dir;
|
host->dma_dir = dma_data_dir;
|
||||||
host->slave_dirn = slave_dirn;
|
host->slave_dirn = slave_dirn;
|
||||||
desc = mxs_mmc_prep_dma(host, 1);
|
desc = mxs_mmc_prep_dma(host, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
if (!desc)
|
if (!desc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|||||||
@@ -304,9 +304,6 @@ config MTD_OOPS
|
|||||||
buffer in a flash partition where it can be read back at some
|
buffer in a flash partition where it can be read back at some
|
||||||
later point.
|
later point.
|
||||||
|
|
||||||
To use, add console=ttyMTDx to the kernel command line,
|
|
||||||
where x is the MTD device number to use.
|
|
||||||
|
|
||||||
config MTD_SWAP
|
config MTD_SWAP
|
||||||
tristate "Swap on MTD device support"
|
tristate "Swap on MTD device support"
|
||||||
depends on MTD && SWAP
|
depends on MTD && SWAP
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **
|
|||||||
|
|
||||||
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
|
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, void **virt, resource_size_t *phys);
|
size_t *retlen, void **virt, resource_size_t *phys);
|
||||||
static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
|
static int cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
|
||||||
|
|
||||||
static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
|
static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
|
||||||
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
|
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
|
||||||
@@ -262,9 +262,9 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd)
|
|||||||
static void fixup_use_point(struct mtd_info *mtd)
|
static void fixup_use_point(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct map_info *map = mtd->priv;
|
struct map_info *map = mtd->priv;
|
||||||
if (!mtd->point && map_is_linear(map)) {
|
if (!mtd->_point && map_is_linear(map)) {
|
||||||
mtd->point = cfi_intelext_point;
|
mtd->_point = cfi_intelext_point;
|
||||||
mtd->unpoint = cfi_intelext_unpoint;
|
mtd->_unpoint = cfi_intelext_unpoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,8 +274,8 @@ static void fixup_use_write_buffers(struct mtd_info *mtd)
|
|||||||
struct cfi_private *cfi = map->fldrv_priv;
|
struct cfi_private *cfi = map->fldrv_priv;
|
||||||
if (cfi->cfiq->BufWriteTimeoutTyp) {
|
if (cfi->cfiq->BufWriteTimeoutTyp) {
|
||||||
printk(KERN_INFO "Using buffer write method\n" );
|
printk(KERN_INFO "Using buffer write method\n" );
|
||||||
mtd->write = cfi_intelext_write_buffers;
|
mtd->_write = cfi_intelext_write_buffers;
|
||||||
mtd->writev = cfi_intelext_writev;
|
mtd->_writev = cfi_intelext_writev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,15 +443,15 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
|
|||||||
mtd->type = MTD_NORFLASH;
|
mtd->type = MTD_NORFLASH;
|
||||||
|
|
||||||
/* Fill in the default mtd operations */
|
/* Fill in the default mtd operations */
|
||||||
mtd->erase = cfi_intelext_erase_varsize;
|
mtd->_erase = cfi_intelext_erase_varsize;
|
||||||
mtd->read = cfi_intelext_read;
|
mtd->_read = cfi_intelext_read;
|
||||||
mtd->write = cfi_intelext_write_words;
|
mtd->_write = cfi_intelext_write_words;
|
||||||
mtd->sync = cfi_intelext_sync;
|
mtd->_sync = cfi_intelext_sync;
|
||||||
mtd->lock = cfi_intelext_lock;
|
mtd->_lock = cfi_intelext_lock;
|
||||||
mtd->unlock = cfi_intelext_unlock;
|
mtd->_unlock = cfi_intelext_unlock;
|
||||||
mtd->is_locked = cfi_intelext_is_locked;
|
mtd->_is_locked = cfi_intelext_is_locked;
|
||||||
mtd->suspend = cfi_intelext_suspend;
|
mtd->_suspend = cfi_intelext_suspend;
|
||||||
mtd->resume = cfi_intelext_resume;
|
mtd->_resume = cfi_intelext_resume;
|
||||||
mtd->flags = MTD_CAP_NORFLASH;
|
mtd->flags = MTD_CAP_NORFLASH;
|
||||||
mtd->name = map->name;
|
mtd->name = map->name;
|
||||||
mtd->writesize = 1;
|
mtd->writesize = 1;
|
||||||
@@ -600,12 +600,12 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MTD_OTP
|
#ifdef CONFIG_MTD_OTP
|
||||||
mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
|
mtd->_read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
|
||||||
mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
|
mtd->_read_user_prot_reg = cfi_intelext_read_user_prot_reg;
|
||||||
mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg;
|
mtd->_write_user_prot_reg = cfi_intelext_write_user_prot_reg;
|
||||||
mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
|
mtd->_lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
|
||||||
mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info;
|
mtd->_get_fact_prot_info = cfi_intelext_get_fact_prot_info;
|
||||||
mtd->get_user_prot_info = cfi_intelext_get_user_prot_info;
|
mtd->_get_user_prot_info = cfi_intelext_get_user_prot_info;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This function has the potential to distort the reality
|
/* This function has the potential to distort the reality
|
||||||
@@ -1017,8 +1017,6 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
|
|||||||
case FL_READY:
|
case FL_READY:
|
||||||
case FL_STATUS:
|
case FL_STATUS:
|
||||||
case FL_JEDEC_QUERY:
|
case FL_JEDEC_QUERY:
|
||||||
/* We should really make set_vpp() count, rather than doing this */
|
|
||||||
DISABLE_VPP(map);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk(KERN_ERR "%s: put_chip() called with oldstate %d!!\n", map->name, chip->oldstate);
|
printk(KERN_ERR "%s: put_chip() called with oldstate %d!!\n", map->name, chip->oldstate);
|
||||||
@@ -1324,7 +1322,7 @@ static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
int chipnum;
|
int chipnum;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!map->virt || (from + len > mtd->size))
|
if (!map->virt)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Now lock the chip(s) to POINT state */
|
/* Now lock the chip(s) to POINT state */
|
||||||
@@ -1334,7 +1332,6 @@ static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
ofs = from - (chipnum << cfi->chipshift);
|
ofs = from - (chipnum << cfi->chipshift);
|
||||||
|
|
||||||
*virt = map->virt + cfi->chips[chipnum].start + ofs;
|
*virt = map->virt + cfi->chips[chipnum].start + ofs;
|
||||||
*retlen = 0;
|
|
||||||
if (phys)
|
if (phys)
|
||||||
*phys = map->phys + cfi->chips[chipnum].start + ofs;
|
*phys = map->phys + cfi->chips[chipnum].start + ofs;
|
||||||
|
|
||||||
@@ -1369,12 +1366,12 @@ static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
static int cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
||||||
{
|
{
|
||||||
struct map_info *map = mtd->priv;
|
struct map_info *map = mtd->priv;
|
||||||
struct cfi_private *cfi = map->fldrv_priv;
|
struct cfi_private *cfi = map->fldrv_priv;
|
||||||
unsigned long ofs;
|
unsigned long ofs;
|
||||||
int chipnum;
|
int chipnum, err = 0;
|
||||||
|
|
||||||
/* Now unlock the chip(s) POINT state */
|
/* Now unlock the chip(s) POINT state */
|
||||||
|
|
||||||
@@ -1382,7 +1379,7 @@ static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
|||||||
chipnum = (from >> cfi->chipshift);
|
chipnum = (from >> cfi->chipshift);
|
||||||
ofs = from - (chipnum << cfi->chipshift);
|
ofs = from - (chipnum << cfi->chipshift);
|
||||||
|
|
||||||
while (len) {
|
while (len && !err) {
|
||||||
unsigned long thislen;
|
unsigned long thislen;
|
||||||
struct flchip *chip;
|
struct flchip *chip;
|
||||||
|
|
||||||
@@ -1400,8 +1397,10 @@ static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
|||||||
chip->ref_point_counter--;
|
chip->ref_point_counter--;
|
||||||
if(chip->ref_point_counter == 0)
|
if(chip->ref_point_counter == 0)
|
||||||
chip->state = FL_READY;
|
chip->state = FL_READY;
|
||||||
} else
|
} else {
|
||||||
printk(KERN_ERR "%s: Warning: unpoint called on non pointed region\n", map->name); /* Should this give an error? */
|
printk(KERN_ERR "%s: Error: unpoint called on non pointed region\n", map->name);
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
put_chip(map, chip, chip->start);
|
put_chip(map, chip, chip->start);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
@@ -1410,6 +1409,8 @@ static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
|||||||
ofs = 0;
|
ofs = 0;
|
||||||
chipnum++;
|
chipnum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
|
static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
|
||||||
@@ -1456,8 +1457,6 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz
|
|||||||
chipnum = (from >> cfi->chipshift);
|
chipnum = (from >> cfi->chipshift);
|
||||||
ofs = from - (chipnum << cfi->chipshift);
|
ofs = from - (chipnum << cfi->chipshift);
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
unsigned long thislen;
|
unsigned long thislen;
|
||||||
|
|
||||||
@@ -1551,7 +1550,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
|
|||||||
}
|
}
|
||||||
|
|
||||||
xip_enable(map, chip, adr);
|
xip_enable(map, chip, adr);
|
||||||
out: put_chip(map, chip, adr);
|
out: DISABLE_VPP(map);
|
||||||
|
put_chip(map, chip, adr);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1565,10 +1565,6 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
|
|||||||
int chipnum;
|
int chipnum;
|
||||||
unsigned long ofs;
|
unsigned long ofs;
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
chipnum = to >> cfi->chipshift;
|
chipnum = to >> cfi->chipshift;
|
||||||
ofs = to - (chipnum << cfi->chipshift);
|
ofs = to - (chipnum << cfi->chipshift);
|
||||||
|
|
||||||
@@ -1794,7 +1790,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
|
|||||||
}
|
}
|
||||||
|
|
||||||
xip_enable(map, chip, cmd_adr);
|
xip_enable(map, chip, cmd_adr);
|
||||||
out: put_chip(map, chip, cmd_adr);
|
out: DISABLE_VPP(map);
|
||||||
|
put_chip(map, chip, cmd_adr);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1813,7 +1810,6 @@ static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs,
|
|||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
len += vecs[i].iov_len;
|
len += vecs[i].iov_len;
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
if (!len)
|
if (!len)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -1932,6 +1928,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
|
|||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
} else if (chipstatus & 0x20 && retries--) {
|
} else if (chipstatus & 0x20 && retries--) {
|
||||||
printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
|
printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
|
||||||
|
DISABLE_VPP(map);
|
||||||
put_chip(map, chip, adr);
|
put_chip(map, chip, adr);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
goto retry;
|
goto retry;
|
||||||
@@ -1944,7 +1941,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
|
|||||||
}
|
}
|
||||||
|
|
||||||
xip_enable(map, chip, adr);
|
xip_enable(map, chip, adr);
|
||||||
out: put_chip(map, chip, adr);
|
out: DISABLE_VPP(map);
|
||||||
|
put_chip(map, chip, adr);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -2086,7 +2084,8 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
|
|||||||
}
|
}
|
||||||
|
|
||||||
xip_enable(map, chip, adr);
|
xip_enable(map, chip, adr);
|
||||||
out: put_chip(map, chip, adr);
|
out: DISABLE_VPP(map);
|
||||||
|
put_chip(map, chip, adr);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -2483,7 +2482,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
|
|||||||
allowed to. Or should we return -EAGAIN, because the upper layers
|
allowed to. Or should we return -EAGAIN, because the upper layers
|
||||||
ought to have already shut down anything which was using the device
|
ought to have already shut down anything which was using the device
|
||||||
anyway? The latter for now. */
|
anyway? The latter for now. */
|
||||||
printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->oldstate);
|
printk(KERN_NOTICE "Flash device refused suspend due to active operation (state %d)\n", chip->state);
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
case FL_PM_SUSPENDED:
|
case FL_PM_SUSPENDED:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ static void cfi_amdstd_resume (struct mtd_info *);
|
|||||||
static int cfi_amdstd_reboot(struct notifier_block *, unsigned long, void *);
|
static int cfi_amdstd_reboot(struct notifier_block *, unsigned long, void *);
|
||||||
static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
|
static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
|
||||||
|
|
||||||
|
static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
|
size_t *retlen, const u_char *buf);
|
||||||
|
|
||||||
static void cfi_amdstd_destroy(struct mtd_info *);
|
static void cfi_amdstd_destroy(struct mtd_info *);
|
||||||
|
|
||||||
struct mtd_info *cfi_cmdset_0002(struct map_info *, int);
|
struct mtd_info *cfi_cmdset_0002(struct map_info *, int);
|
||||||
@@ -189,7 +192,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd)
|
|||||||
struct cfi_private *cfi = map->fldrv_priv;
|
struct cfi_private *cfi = map->fldrv_priv;
|
||||||
if (cfi->cfiq->BufWriteTimeoutTyp) {
|
if (cfi->cfiq->BufWriteTimeoutTyp) {
|
||||||
pr_debug("Using buffer write method\n" );
|
pr_debug("Using buffer write method\n" );
|
||||||
mtd->write = cfi_amdstd_write_buffers;
|
mtd->_write = cfi_amdstd_write_buffers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,8 +231,8 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd)
|
|||||||
static void fixup_use_secsi(struct mtd_info *mtd)
|
static void fixup_use_secsi(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
/* Setup for chips with a secsi area */
|
/* Setup for chips with a secsi area */
|
||||||
mtd->read_user_prot_reg = cfi_amdstd_secsi_read;
|
mtd->_read_user_prot_reg = cfi_amdstd_secsi_read;
|
||||||
mtd->read_fact_prot_reg = cfi_amdstd_secsi_read;
|
mtd->_read_fact_prot_reg = cfi_amdstd_secsi_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fixup_use_erase_chip(struct mtd_info *mtd)
|
static void fixup_use_erase_chip(struct mtd_info *mtd)
|
||||||
@@ -238,7 +241,7 @@ static void fixup_use_erase_chip(struct mtd_info *mtd)
|
|||||||
struct cfi_private *cfi = map->fldrv_priv;
|
struct cfi_private *cfi = map->fldrv_priv;
|
||||||
if ((cfi->cfiq->NumEraseRegions == 1) &&
|
if ((cfi->cfiq->NumEraseRegions == 1) &&
|
||||||
((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) {
|
((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) {
|
||||||
mtd->erase = cfi_amdstd_erase_chip;
|
mtd->_erase = cfi_amdstd_erase_chip;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -249,8 +252,8 @@ static void fixup_use_erase_chip(struct mtd_info *mtd)
|
|||||||
*/
|
*/
|
||||||
static void fixup_use_atmel_lock(struct mtd_info *mtd)
|
static void fixup_use_atmel_lock(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
mtd->lock = cfi_atmel_lock;
|
mtd->_lock = cfi_atmel_lock;
|
||||||
mtd->unlock = cfi_atmel_unlock;
|
mtd->_unlock = cfi_atmel_unlock;
|
||||||
mtd->flags |= MTD_POWERUP_LOCK;
|
mtd->flags |= MTD_POWERUP_LOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,12 +432,12 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
|
|||||||
mtd->type = MTD_NORFLASH;
|
mtd->type = MTD_NORFLASH;
|
||||||
|
|
||||||
/* Fill in the default mtd operations */
|
/* Fill in the default mtd operations */
|
||||||
mtd->erase = cfi_amdstd_erase_varsize;
|
mtd->_erase = cfi_amdstd_erase_varsize;
|
||||||
mtd->write = cfi_amdstd_write_words;
|
mtd->_write = cfi_amdstd_write_words;
|
||||||
mtd->read = cfi_amdstd_read;
|
mtd->_read = cfi_amdstd_read;
|
||||||
mtd->sync = cfi_amdstd_sync;
|
mtd->_sync = cfi_amdstd_sync;
|
||||||
mtd->suspend = cfi_amdstd_suspend;
|
mtd->_suspend = cfi_amdstd_suspend;
|
||||||
mtd->resume = cfi_amdstd_resume;
|
mtd->_resume = cfi_amdstd_resume;
|
||||||
mtd->flags = MTD_CAP_NORFLASH;
|
mtd->flags = MTD_CAP_NORFLASH;
|
||||||
mtd->name = map->name;
|
mtd->name = map->name;
|
||||||
mtd->writesize = 1;
|
mtd->writesize = 1;
|
||||||
@@ -443,6 +446,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
|
|||||||
pr_debug("MTD %s(): write buffer size %d\n", __func__,
|
pr_debug("MTD %s(): write buffer size %d\n", __func__,
|
||||||
mtd->writebufsize);
|
mtd->writebufsize);
|
||||||
|
|
||||||
|
mtd->_panic_write = cfi_amdstd_panic_write;
|
||||||
mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot;
|
mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot;
|
||||||
|
|
||||||
if (cfi->cfi_mode==CFI_MODE_CFI){
|
if (cfi->cfi_mode==CFI_MODE_CFI){
|
||||||
@@ -770,8 +774,6 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
|
|||||||
|
|
||||||
case FL_READY:
|
case FL_READY:
|
||||||
case FL_STATUS:
|
case FL_STATUS:
|
||||||
/* We should really make set_vpp() count, rather than doing this */
|
|
||||||
DISABLE_VPP(map);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate);
|
printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate);
|
||||||
@@ -1013,13 +1015,9 @@ static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* ofs: offset within the first chip that the first read should start */
|
/* ofs: offset within the first chip that the first read should start */
|
||||||
|
|
||||||
chipnum = (from >> cfi->chipshift);
|
chipnum = (from >> cfi->chipshift);
|
||||||
ofs = from - (chipnum << cfi->chipshift);
|
ofs = from - (chipnum << cfi->chipshift);
|
||||||
|
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
unsigned long thislen;
|
unsigned long thislen;
|
||||||
|
|
||||||
@@ -1097,16 +1095,11 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
int chipnum;
|
int chipnum;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
|
||||||
/* ofs: offset within the first chip that the first read should start */
|
/* ofs: offset within the first chip that the first read should start */
|
||||||
|
|
||||||
/* 8 secsi bytes per chip */
|
/* 8 secsi bytes per chip */
|
||||||
chipnum=from>>3;
|
chipnum=from>>3;
|
||||||
ofs=from & 7;
|
ofs=from & 7;
|
||||||
|
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
unsigned long thislen;
|
unsigned long thislen;
|
||||||
|
|
||||||
@@ -1234,6 +1227,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
|
|||||||
xip_enable(map, chip, adr);
|
xip_enable(map, chip, adr);
|
||||||
op_done:
|
op_done:
|
||||||
chip->state = FL_READY;
|
chip->state = FL_READY;
|
||||||
|
DISABLE_VPP(map);
|
||||||
put_chip(map, chip, adr);
|
put_chip(map, chip, adr);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
|
|
||||||
@@ -1251,10 +1245,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
unsigned long ofs, chipstart;
|
unsigned long ofs, chipstart;
|
||||||
DECLARE_WAITQUEUE(wait, current);
|
DECLARE_WAITQUEUE(wait, current);
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
chipnum = to >> cfi->chipshift;
|
chipnum = to >> cfi->chipshift;
|
||||||
ofs = to - (chipnum << cfi->chipshift);
|
ofs = to - (chipnum << cfi->chipshift);
|
||||||
chipstart = cfi->chips[chipnum].start;
|
chipstart = cfi->chips[chipnum].start;
|
||||||
@@ -1476,6 +1466,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
|
|||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
op_done:
|
op_done:
|
||||||
chip->state = FL_READY;
|
chip->state = FL_READY;
|
||||||
|
DISABLE_VPP(map);
|
||||||
put_chip(map, chip, adr);
|
put_chip(map, chip, adr);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
|
|
||||||
@@ -1493,10 +1484,6 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
int chipnum;
|
int chipnum;
|
||||||
unsigned long ofs;
|
unsigned long ofs;
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
chipnum = to >> cfi->chipshift;
|
chipnum = to >> cfi->chipshift;
|
||||||
ofs = to - (chipnum << cfi->chipshift);
|
ofs = to - (chipnum << cfi->chipshift);
|
||||||
|
|
||||||
@@ -1562,6 +1549,238 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for the flash chip to become ready to write data
|
||||||
|
*
|
||||||
|
* This is only called during the panic_write() path. When panic_write()
|
||||||
|
* is called, the kernel is in the process of a panic, and will soon be
|
||||||
|
* dead. Therefore we don't take any locks, and attempt to get access
|
||||||
|
* to the chip as soon as possible.
|
||||||
|
*/
|
||||||
|
static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
|
||||||
|
unsigned long adr)
|
||||||
|
{
|
||||||
|
struct cfi_private *cfi = map->fldrv_priv;
|
||||||
|
int retries = 10;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the driver thinks the chip is idle, and no toggle bits
|
||||||
|
* are changing, then the chip is actually idle for sure.
|
||||||
|
*/
|
||||||
|
if (chip->state == FL_READY && chip_ready(map, adr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try several times to reset the chip and then wait for it
|
||||||
|
* to become idle. The upper limit of a few milliseconds of
|
||||||
|
* delay isn't a big problem: the kernel is dying anyway. It
|
||||||
|
* is more important to save the messages.
|
||||||
|
*/
|
||||||
|
while (retries > 0) {
|
||||||
|
const unsigned long timeo = (HZ / 1000) + 1;
|
||||||
|
|
||||||
|
/* send the reset command */
|
||||||
|
map_write(map, CMD(0xF0), chip->start);
|
||||||
|
|
||||||
|
/* wait for the chip to become ready */
|
||||||
|
for (i = 0; i < jiffies_to_usecs(timeo); i++) {
|
||||||
|
if (chip_ready(map, adr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
udelay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the chip never became ready */
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out one word of data to a single flash chip during a kernel panic
|
||||||
|
*
|
||||||
|
* This is only called during the panic_write() path. When panic_write()
|
||||||
|
* is called, the kernel is in the process of a panic, and will soon be
|
||||||
|
* dead. Therefore we don't take any locks, and attempt to get access
|
||||||
|
* to the chip as soon as possible.
|
||||||
|
*
|
||||||
|
* The implementation of this routine is intentionally similar to
|
||||||
|
* do_write_oneword(), in order to ease code maintenance.
|
||||||
|
*/
|
||||||
|
static int do_panic_write_oneword(struct map_info *map, struct flchip *chip,
|
||||||
|
unsigned long adr, map_word datum)
|
||||||
|
{
|
||||||
|
const unsigned long uWriteTimeout = (HZ / 1000) + 1;
|
||||||
|
struct cfi_private *cfi = map->fldrv_priv;
|
||||||
|
int retry_cnt = 0;
|
||||||
|
map_word oldd;
|
||||||
|
int ret = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
adr += chip->start;
|
||||||
|
|
||||||
|
ret = cfi_amdstd_panic_wait(map, chip, adr);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
pr_debug("MTD %s(): PANIC WRITE 0x%.8lx(0x%.8lx)\n",
|
||||||
|
__func__, adr, datum.x[0]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for a NOP for the case when the datum to write is already
|
||||||
|
* present - it saves time and works around buggy chips that corrupt
|
||||||
|
* data at other locations when 0xff is written to a location that
|
||||||
|
* already contains 0xff.
|
||||||
|
*/
|
||||||
|
oldd = map_read(map, adr);
|
||||||
|
if (map_word_equal(map, oldd, datum)) {
|
||||||
|
pr_debug("MTD %s(): NOP\n", __func__);
|
||||||
|
goto op_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ENABLE_VPP(map);
|
||||||
|
|
||||||
|
retry:
|
||||||
|
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);
|
||||||
|
map_write(map, datum, adr);
|
||||||
|
|
||||||
|
for (i = 0; i < jiffies_to_usecs(uWriteTimeout); i++) {
|
||||||
|
if (chip_ready(map, adr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
udelay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chip_good(map, adr, datum)) {
|
||||||
|
/* reset on all failures. */
|
||||||
|
map_write(map, CMD(0xF0), chip->start);
|
||||||
|
/* FIXME - should have reset delay before continuing */
|
||||||
|
|
||||||
|
if (++retry_cnt <= MAX_WORD_RETRIES)
|
||||||
|
goto retry;
|
||||||
|
|
||||||
|
ret = -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
op_done:
|
||||||
|
DISABLE_VPP(map);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out some data during a kernel panic
|
||||||
|
*
|
||||||
|
* This is used by the mtdoops driver to save the dying messages from a
|
||||||
|
* kernel which has panic'd.
|
||||||
|
*
|
||||||
|
* This routine ignores all of the locking used throughout the rest of the
|
||||||
|
* driver, in order to ensure that the data gets written out no matter what
|
||||||
|
* state this driver (and the flash chip itself) was in when the kernel crashed.
|
||||||
|
*
|
||||||
|
* The implementation of this routine is intentionally similar to
|
||||||
|
* cfi_amdstd_write_words(), in order to ease code maintenance.
|
||||||
|
*/
|
||||||
|
static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
|
size_t *retlen, const u_char *buf)
|
||||||
|
{
|
||||||
|
struct map_info *map = mtd->priv;
|
||||||
|
struct cfi_private *cfi = map->fldrv_priv;
|
||||||
|
unsigned long ofs, chipstart;
|
||||||
|
int ret = 0;
|
||||||
|
int chipnum;
|
||||||
|
|
||||||
|
chipnum = to >> cfi->chipshift;
|
||||||
|
ofs = to - (chipnum << cfi->chipshift);
|
||||||
|
chipstart = cfi->chips[chipnum].start;
|
||||||
|
|
||||||
|
/* If it's not bus aligned, do the first byte write */
|
||||||
|
if (ofs & (map_bankwidth(map) - 1)) {
|
||||||
|
unsigned long bus_ofs = ofs & ~(map_bankwidth(map) - 1);
|
||||||
|
int i = ofs - bus_ofs;
|
||||||
|
int n = 0;
|
||||||
|
map_word tmp_buf;
|
||||||
|
|
||||||
|
ret = cfi_amdstd_panic_wait(map, &cfi->chips[chipnum], bus_ofs);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Load 'tmp_buf' with old contents of flash */
|
||||||
|
tmp_buf = map_read(map, bus_ofs + chipstart);
|
||||||
|
|
||||||
|
/* Number of bytes to copy from buffer */
|
||||||
|
n = min_t(int, len, map_bankwidth(map) - i);
|
||||||
|
|
||||||
|
tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
|
||||||
|
|
||||||
|
ret = do_panic_write_oneword(map, &cfi->chips[chipnum],
|
||||||
|
bus_ofs, tmp_buf);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ofs += n;
|
||||||
|
buf += n;
|
||||||
|
(*retlen) += n;
|
||||||
|
len -= n;
|
||||||
|
|
||||||
|
if (ofs >> cfi->chipshift) {
|
||||||
|
chipnum++;
|
||||||
|
ofs = 0;
|
||||||
|
if (chipnum == cfi->numchips)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We are now aligned, write as much as possible */
|
||||||
|
while (len >= map_bankwidth(map)) {
|
||||||
|
map_word datum;
|
||||||
|
|
||||||
|
datum = map_word_load(map, buf);
|
||||||
|
|
||||||
|
ret = do_panic_write_oneword(map, &cfi->chips[chipnum],
|
||||||
|
ofs, datum);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ofs += map_bankwidth(map);
|
||||||
|
buf += map_bankwidth(map);
|
||||||
|
(*retlen) += map_bankwidth(map);
|
||||||
|
len -= map_bankwidth(map);
|
||||||
|
|
||||||
|
if (ofs >> cfi->chipshift) {
|
||||||
|
chipnum++;
|
||||||
|
ofs = 0;
|
||||||
|
if (chipnum == cfi->numchips)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
chipstart = cfi->chips[chipnum].start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the trailing bytes if any */
|
||||||
|
if (len & (map_bankwidth(map) - 1)) {
|
||||||
|
map_word tmp_buf;
|
||||||
|
|
||||||
|
ret = cfi_amdstd_panic_wait(map, &cfi->chips[chipnum], ofs);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
tmp_buf = map_read(map, ofs + chipstart);
|
||||||
|
|
||||||
|
tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
|
||||||
|
|
||||||
|
ret = do_panic_write_oneword(map, &cfi->chips[chipnum],
|
||||||
|
ofs, tmp_buf);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
(*retlen) += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle devices with one erase region, that only implement
|
* Handle devices with one erase region, that only implement
|
||||||
@@ -1649,6 +1868,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
|
|||||||
|
|
||||||
chip->state = FL_READY;
|
chip->state = FL_READY;
|
||||||
xip_enable(map, chip, adr);
|
xip_enable(map, chip, adr);
|
||||||
|
DISABLE_VPP(map);
|
||||||
put_chip(map, chip, adr);
|
put_chip(map, chip, adr);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
|
|
||||||
@@ -1739,6 +1959,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
|
|||||||
}
|
}
|
||||||
|
|
||||||
chip->state = FL_READY;
|
chip->state = FL_READY;
|
||||||
|
DISABLE_VPP(map);
|
||||||
put_chip(map, chip, adr);
|
put_chip(map, chip, adr);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -228,15 +228,15 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Also select the correct geometry setup too */
|
/* Also select the correct geometry setup too */
|
||||||
mtd->erase = cfi_staa_erase_varsize;
|
mtd->_erase = cfi_staa_erase_varsize;
|
||||||
mtd->read = cfi_staa_read;
|
mtd->_read = cfi_staa_read;
|
||||||
mtd->write = cfi_staa_write_buffers;
|
mtd->_write = cfi_staa_write_buffers;
|
||||||
mtd->writev = cfi_staa_writev;
|
mtd->_writev = cfi_staa_writev;
|
||||||
mtd->sync = cfi_staa_sync;
|
mtd->_sync = cfi_staa_sync;
|
||||||
mtd->lock = cfi_staa_lock;
|
mtd->_lock = cfi_staa_lock;
|
||||||
mtd->unlock = cfi_staa_unlock;
|
mtd->_unlock = cfi_staa_unlock;
|
||||||
mtd->suspend = cfi_staa_suspend;
|
mtd->_suspend = cfi_staa_suspend;
|
||||||
mtd->resume = cfi_staa_resume;
|
mtd->_resume = cfi_staa_resume;
|
||||||
mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE;
|
mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE;
|
||||||
mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
|
mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
|
||||||
mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
|
mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
|
||||||
@@ -394,8 +394,6 @@ static int cfi_staa_read (struct mtd_info *mtd, loff_t from, size_t len, size_t
|
|||||||
chipnum = (from >> cfi->chipshift);
|
chipnum = (from >> cfi->chipshift);
|
||||||
ofs = from - (chipnum << cfi->chipshift);
|
ofs = from - (chipnum << cfi->chipshift);
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
unsigned long thislen;
|
unsigned long thislen;
|
||||||
|
|
||||||
@@ -617,10 +615,6 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to,
|
|||||||
int chipnum;
|
int chipnum;
|
||||||
unsigned long ofs;
|
unsigned long ofs;
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
chipnum = to >> cfi->chipshift;
|
chipnum = to >> cfi->chipshift;
|
||||||
ofs = to - (chipnum << cfi->chipshift);
|
ofs = to - (chipnum << cfi->chipshift);
|
||||||
|
|
||||||
@@ -904,12 +898,6 @@ static int cfi_staa_erase_varsize(struct mtd_info *mtd,
|
|||||||
int i, first;
|
int i, first;
|
||||||
struct mtd_erase_region_info *regions = mtd->eraseregions;
|
struct mtd_erase_region_info *regions = mtd->eraseregions;
|
||||||
|
|
||||||
if (instr->addr > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if ((instr->len + instr->addr) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Check that both start and end of the requested erase are
|
/* Check that both start and end of the requested erase are
|
||||||
* aligned with the erasesize at the appropriate addresses.
|
* aligned with the erasesize at the appropriate addresses.
|
||||||
*/
|
*/
|
||||||
@@ -1155,9 +1143,6 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
|||||||
if (len & (mtd->erasesize -1))
|
if (len & (mtd->erasesize -1))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if ((len + ofs) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
chipnum = ofs >> cfi->chipshift;
|
chipnum = ofs >> cfi->chipshift;
|
||||||
adr = ofs - (chipnum << cfi->chipshift);
|
adr = ofs - (chipnum << cfi->chipshift);
|
||||||
|
|
||||||
|
|||||||
@@ -173,12 +173,6 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
|
|||||||
int i, first;
|
int i, first;
|
||||||
struct mtd_erase_region_info *regions = mtd->eraseregions;
|
struct mtd_erase_region_info *regions = mtd->eraseregions;
|
||||||
|
|
||||||
if (ofs > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if ((len + ofs) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Check that both start and end of the requested erase are
|
/* Check that both start and end of the requested erase are
|
||||||
* aligned with the erasesize at the appropriate addresses.
|
* aligned with the erasesize at the appropriate addresses.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ static void fixup_use_fwh_lock(struct mtd_info *mtd)
|
|||||||
{
|
{
|
||||||
printk(KERN_NOTICE "using fwh lock/unlock method\n");
|
printk(KERN_NOTICE "using fwh lock/unlock method\n");
|
||||||
/* Setup for the chips with the fwh lock method */
|
/* Setup for the chips with the fwh lock method */
|
||||||
mtd->lock = fwh_lock_varsize;
|
mtd->_lock = fwh_lock_varsize;
|
||||||
mtd->unlock = fwh_unlock_varsize;
|
mtd->_unlock = fwh_unlock_varsize;
|
||||||
}
|
}
|
||||||
#endif /* FWH_LOCK_H */
|
#endif /* FWH_LOCK_H */
|
||||||
|
|||||||
@@ -55,10 +55,10 @@ static struct mtd_info *map_absent_probe(struct map_info *map)
|
|||||||
mtd->name = map->name;
|
mtd->name = map->name;
|
||||||
mtd->type = MTD_ABSENT;
|
mtd->type = MTD_ABSENT;
|
||||||
mtd->size = map->size;
|
mtd->size = map->size;
|
||||||
mtd->erase = map_absent_erase;
|
mtd->_erase = map_absent_erase;
|
||||||
mtd->read = map_absent_read;
|
mtd->_read = map_absent_read;
|
||||||
mtd->write = map_absent_write;
|
mtd->_write = map_absent_write;
|
||||||
mtd->sync = map_absent_sync;
|
mtd->_sync = map_absent_sync;
|
||||||
mtd->flags = 0;
|
mtd->flags = 0;
|
||||||
mtd->erasesize = PAGE_SIZE;
|
mtd->erasesize = PAGE_SIZE;
|
||||||
mtd->writesize = 1;
|
mtd->writesize = 1;
|
||||||
@@ -70,13 +70,11 @@ static struct mtd_info *map_absent_probe(struct map_info *map)
|
|||||||
|
|
||||||
static int map_absent_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
|
static int map_absent_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
*retlen = 0;
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
|
static int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
|
||||||
{
|
{
|
||||||
*retlen = 0;
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,11 +64,11 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
|
|||||||
mtd->name = map->name;
|
mtd->name = map->name;
|
||||||
mtd->type = MTD_RAM;
|
mtd->type = MTD_RAM;
|
||||||
mtd->size = map->size;
|
mtd->size = map->size;
|
||||||
mtd->erase = mapram_erase;
|
mtd->_erase = mapram_erase;
|
||||||
mtd->get_unmapped_area = mapram_unmapped_area;
|
mtd->_get_unmapped_area = mapram_unmapped_area;
|
||||||
mtd->read = mapram_read;
|
mtd->_read = mapram_read;
|
||||||
mtd->write = mapram_write;
|
mtd->_write = mapram_write;
|
||||||
mtd->sync = mapram_nop;
|
mtd->_sync = mapram_nop;
|
||||||
mtd->flags = MTD_CAP_RAM;
|
mtd->flags = MTD_CAP_RAM;
|
||||||
mtd->writesize = 1;
|
mtd->writesize = 1;
|
||||||
|
|
||||||
@@ -122,14 +122,10 @@ static int mapram_erase (struct mtd_info *mtd, struct erase_info *instr)
|
|||||||
unsigned long i;
|
unsigned long i;
|
||||||
|
|
||||||
allff = map_word_ff(map);
|
allff = map_word_ff(map);
|
||||||
|
|
||||||
for (i=0; i<instr->len; i += map_bankwidth(map))
|
for (i=0; i<instr->len; i += map_bankwidth(map))
|
||||||
map_write(map, allff, instr->addr + i);
|
map_write(map, allff, instr->addr + i);
|
||||||
|
|
||||||
instr->state = MTD_ERASE_DONE;
|
instr->state = MTD_ERASE_DONE;
|
||||||
|
|
||||||
mtd_erase_callback(instr);
|
mtd_erase_callback(instr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,11 +41,11 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
|
|||||||
mtd->name = map->name;
|
mtd->name = map->name;
|
||||||
mtd->type = MTD_ROM;
|
mtd->type = MTD_ROM;
|
||||||
mtd->size = map->size;
|
mtd->size = map->size;
|
||||||
mtd->get_unmapped_area = maprom_unmapped_area;
|
mtd->_get_unmapped_area = maprom_unmapped_area;
|
||||||
mtd->read = maprom_read;
|
mtd->_read = maprom_read;
|
||||||
mtd->write = maprom_write;
|
mtd->_write = maprom_write;
|
||||||
mtd->sync = maprom_nop;
|
mtd->_sync = maprom_nop;
|
||||||
mtd->erase = maprom_erase;
|
mtd->_erase = maprom_erase;
|
||||||
mtd->flags = MTD_CAP_ROM;
|
mtd->flags = MTD_CAP_ROM;
|
||||||
mtd->erasesize = map->size;
|
mtd->erasesize = map->size;
|
||||||
mtd->writesize = 1;
|
mtd->writesize = 1;
|
||||||
@@ -85,8 +85,7 @@ static void maprom_nop(struct mtd_info *mtd)
|
|||||||
|
|
||||||
static int maprom_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
|
static int maprom_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
|
||||||
{
|
{
|
||||||
printk(KERN_NOTICE "maprom_write called\n");
|
return -EROFS;
|
||||||
return -EIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int maprom_erase (struct mtd_info *mtd, struct erase_info *info)
|
static int maprom_erase (struct mtd_info *mtd, struct erase_info *info)
|
||||||
|
|||||||
@@ -103,6 +103,13 @@ config M25PXX_USE_FAST_READ
|
|||||||
help
|
help
|
||||||
This option enables FAST_READ access supported by ST M25Pxx.
|
This option enables FAST_READ access supported by ST M25Pxx.
|
||||||
|
|
||||||
|
config MTD_SPEAR_SMI
|
||||||
|
tristate "SPEAR MTD NOR Support through SMI controller"
|
||||||
|
depends on PLAT_SPEAR
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
This enable SNOR support on SPEAR platforms using SMI controller
|
||||||
|
|
||||||
config MTD_SST25L
|
config MTD_SST25L
|
||||||
tristate "Support SST25L (non JEDEC) SPI Flash chips"
|
tristate "Support SST25L (non JEDEC) SPI Flash chips"
|
||||||
depends on SPI_MASTER
|
depends on SPI_MASTER
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ obj-$(CONFIG_MTD_LART) += lart.o
|
|||||||
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
|
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
|
||||||
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
|
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
|
||||||
obj-$(CONFIG_MTD_M25P80) += m25p80.o
|
obj-$(CONFIG_MTD_M25P80) += m25p80.o
|
||||||
|
obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
|
||||||
obj-$(CONFIG_MTD_SST25L) += sst25l.o
|
obj-$(CONFIG_MTD_SST25L) += sst25l.o
|
||||||
|
|
||||||
CFLAGS_docg3.o += -I$(src)
|
CFLAGS_docg3.o += -I$(src)
|
||||||
@@ -104,14 +104,6 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
int offset = from & (PAGE_SIZE-1);
|
int offset = from & (PAGE_SIZE-1);
|
||||||
int cpylen;
|
int cpylen;
|
||||||
|
|
||||||
if (from > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
if (from + len > mtd->size)
|
|
||||||
len = mtd->size - from;
|
|
||||||
|
|
||||||
if (retlen)
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
if ((offset + len) > PAGE_SIZE)
|
if ((offset + len) > PAGE_SIZE)
|
||||||
cpylen = PAGE_SIZE - offset; // multiple pages
|
cpylen = PAGE_SIZE - offset; // multiple pages
|
||||||
@@ -148,8 +140,6 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
|
|||||||
int offset = to & ~PAGE_MASK; // page offset
|
int offset = to & ~PAGE_MASK; // page offset
|
||||||
int cpylen;
|
int cpylen;
|
||||||
|
|
||||||
if (retlen)
|
|
||||||
*retlen = 0;
|
|
||||||
while (len) {
|
while (len) {
|
||||||
if ((offset+len) > PAGE_SIZE)
|
if ((offset+len) > PAGE_SIZE)
|
||||||
cpylen = PAGE_SIZE - offset; // multiple pages
|
cpylen = PAGE_SIZE - offset; // multiple pages
|
||||||
@@ -188,13 +178,6 @@ static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
struct block2mtd_dev *dev = mtd->priv;
|
struct block2mtd_dev *dev = mtd->priv;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
if (to >= mtd->size)
|
|
||||||
return -ENOSPC;
|
|
||||||
if (to + len > mtd->size)
|
|
||||||
len = mtd->size - to;
|
|
||||||
|
|
||||||
mutex_lock(&dev->write_mutex);
|
mutex_lock(&dev->write_mutex);
|
||||||
err = _block2mtd_write(dev, buf, to, len, retlen);
|
err = _block2mtd_write(dev, buf, to, len, retlen);
|
||||||
mutex_unlock(&dev->write_mutex);
|
mutex_unlock(&dev->write_mutex);
|
||||||
@@ -283,13 +266,14 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
|
|||||||
dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
|
dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
|
||||||
dev->mtd.erasesize = erase_size;
|
dev->mtd.erasesize = erase_size;
|
||||||
dev->mtd.writesize = 1;
|
dev->mtd.writesize = 1;
|
||||||
|
dev->mtd.writebufsize = PAGE_SIZE;
|
||||||
dev->mtd.type = MTD_RAM;
|
dev->mtd.type = MTD_RAM;
|
||||||
dev->mtd.flags = MTD_CAP_RAM;
|
dev->mtd.flags = MTD_CAP_RAM;
|
||||||
dev->mtd.erase = block2mtd_erase;
|
dev->mtd._erase = block2mtd_erase;
|
||||||
dev->mtd.write = block2mtd_write;
|
dev->mtd._write = block2mtd_write;
|
||||||
dev->mtd.writev = mtd_writev;
|
dev->mtd._writev = mtd_writev;
|
||||||
dev->mtd.sync = block2mtd_sync;
|
dev->mtd._sync = block2mtd_sync;
|
||||||
dev->mtd.read = block2mtd_read;
|
dev->mtd._read = block2mtd_read;
|
||||||
dev->mtd.priv = dev;
|
dev->mtd.priv = dev;
|
||||||
dev->mtd.owner = THIS_MODULE;
|
dev->mtd.owner = THIS_MODULE;
|
||||||
|
|
||||||
|
|||||||
@@ -562,14 +562,15 @@ void DoC2k_init(struct mtd_info *mtd)
|
|||||||
|
|
||||||
mtd->type = MTD_NANDFLASH;
|
mtd->type = MTD_NANDFLASH;
|
||||||
mtd->flags = MTD_CAP_NANDFLASH;
|
mtd->flags = MTD_CAP_NANDFLASH;
|
||||||
mtd->writesize = 512;
|
mtd->writebufsize = mtd->writesize = 512;
|
||||||
mtd->oobsize = 16;
|
mtd->oobsize = 16;
|
||||||
|
mtd->ecc_strength = 2;
|
||||||
mtd->owner = THIS_MODULE;
|
mtd->owner = THIS_MODULE;
|
||||||
mtd->erase = doc_erase;
|
mtd->_erase = doc_erase;
|
||||||
mtd->read = doc_read;
|
mtd->_read = doc_read;
|
||||||
mtd->write = doc_write;
|
mtd->_write = doc_write;
|
||||||
mtd->read_oob = doc_read_oob;
|
mtd->_read_oob = doc_read_oob;
|
||||||
mtd->write_oob = doc_write_oob;
|
mtd->_write_oob = doc_write_oob;
|
||||||
this->curfloor = -1;
|
this->curfloor = -1;
|
||||||
this->curchip = -1;
|
this->curchip = -1;
|
||||||
mutex_init(&this->lock);
|
mutex_init(&this->lock);
|
||||||
@@ -602,13 +603,7 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
int i, len256 = 0, ret=0;
|
int i, len256 = 0, ret=0;
|
||||||
size_t left = len;
|
size_t left = len;
|
||||||
|
|
||||||
/* Don't allow read past end of device */
|
|
||||||
if (from >= this->totlen)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
mutex_lock(&this->lock);
|
mutex_lock(&this->lock);
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
while (left) {
|
while (left) {
|
||||||
len = left;
|
len = left;
|
||||||
|
|
||||||
@@ -748,13 +743,7 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
size_t left = len;
|
size_t left = len;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
/* Don't allow write past end of device */
|
|
||||||
if (to >= this->totlen)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
mutex_lock(&this->lock);
|
mutex_lock(&this->lock);
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
while (left) {
|
while (left) {
|
||||||
len = left;
|
len = left;
|
||||||
|
|
||||||
|
|||||||
@@ -346,14 +346,15 @@ void DoCMil_init(struct mtd_info *mtd)
|
|||||||
|
|
||||||
/* FIXME: erase size is not always 8KiB */
|
/* FIXME: erase size is not always 8KiB */
|
||||||
mtd->erasesize = 0x2000;
|
mtd->erasesize = 0x2000;
|
||||||
mtd->writesize = 512;
|
mtd->writebufsize = mtd->writesize = 512;
|
||||||
mtd->oobsize = 16;
|
mtd->oobsize = 16;
|
||||||
|
mtd->ecc_strength = 2;
|
||||||
mtd->owner = THIS_MODULE;
|
mtd->owner = THIS_MODULE;
|
||||||
mtd->erase = doc_erase;
|
mtd->_erase = doc_erase;
|
||||||
mtd->read = doc_read;
|
mtd->_read = doc_read;
|
||||||
mtd->write = doc_write;
|
mtd->_write = doc_write;
|
||||||
mtd->read_oob = doc_read_oob;
|
mtd->_read_oob = doc_read_oob;
|
||||||
mtd->write_oob = doc_write_oob;
|
mtd->_write_oob = doc_write_oob;
|
||||||
this->curfloor = -1;
|
this->curfloor = -1;
|
||||||
this->curchip = -1;
|
this->curchip = -1;
|
||||||
|
|
||||||
@@ -383,10 +384,6 @@ static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
void __iomem *docptr = this->virtadr;
|
void __iomem *docptr = this->virtadr;
|
||||||
struct Nand *mychip = &this->chips[from >> (this->chipshift)];
|
struct Nand *mychip = &this->chips[from >> (this->chipshift)];
|
||||||
|
|
||||||
/* Don't allow read past end of device */
|
|
||||||
if (from >= this->totlen)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Don't allow a single read to cross a 512-byte block boundary */
|
/* Don't allow a single read to cross a 512-byte block boundary */
|
||||||
if (from + len > ((from | 0x1ff) + 1))
|
if (from + len > ((from | 0x1ff) + 1))
|
||||||
len = ((from | 0x1ff) + 1) - from;
|
len = ((from | 0x1ff) + 1) - from;
|
||||||
@@ -494,10 +491,6 @@ static int doc_write (struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
void __iomem *docptr = this->virtadr;
|
void __iomem *docptr = this->virtadr;
|
||||||
struct Nand *mychip = &this->chips[to >> (this->chipshift)];
|
struct Nand *mychip = &this->chips[to >> (this->chipshift)];
|
||||||
|
|
||||||
/* Don't allow write past end of device */
|
|
||||||
if (to >= this->totlen)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* Don't allow a single write to cross a 512-byte block boundary */
|
/* Don't allow a single write to cross a 512-byte block boundary */
|
||||||
if (to + len > ( (to | 0x1ff) + 1))
|
if (to + len > ( (to | 0x1ff) + 1))
|
||||||
@@ -599,7 +592,6 @@ static int doc_write (struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
printk("Error programming flash\n");
|
printk("Error programming flash\n");
|
||||||
/* Error in programming
|
/* Error in programming
|
||||||
FIXME: implement Bad Block Replacement (in nftl.c ??) */
|
FIXME: implement Bad Block Replacement (in nftl.c ??) */
|
||||||
*retlen = 0;
|
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
}
|
}
|
||||||
dummy = ReadDOC(docptr, LastDataRead);
|
dummy = ReadDOC(docptr, LastDataRead);
|
||||||
|
|||||||
@@ -467,14 +467,15 @@ void DoCMilPlus_init(struct mtd_info *mtd)
|
|||||||
|
|
||||||
mtd->type = MTD_NANDFLASH;
|
mtd->type = MTD_NANDFLASH;
|
||||||
mtd->flags = MTD_CAP_NANDFLASH;
|
mtd->flags = MTD_CAP_NANDFLASH;
|
||||||
mtd->writesize = 512;
|
mtd->writebufsize = mtd->writesize = 512;
|
||||||
mtd->oobsize = 16;
|
mtd->oobsize = 16;
|
||||||
|
mtd->ecc_strength = 2;
|
||||||
mtd->owner = THIS_MODULE;
|
mtd->owner = THIS_MODULE;
|
||||||
mtd->erase = doc_erase;
|
mtd->_erase = doc_erase;
|
||||||
mtd->read = doc_read;
|
mtd->_read = doc_read;
|
||||||
mtd->write = doc_write;
|
mtd->_write = doc_write;
|
||||||
mtd->read_oob = doc_read_oob;
|
mtd->_read_oob = doc_read_oob;
|
||||||
mtd->write_oob = doc_write_oob;
|
mtd->_write_oob = doc_write_oob;
|
||||||
this->curfloor = -1;
|
this->curfloor = -1;
|
||||||
this->curchip = -1;
|
this->curchip = -1;
|
||||||
|
|
||||||
@@ -581,10 +582,6 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
void __iomem * docptr = this->virtadr;
|
void __iomem * docptr = this->virtadr;
|
||||||
struct Nand *mychip = &this->chips[from >> (this->chipshift)];
|
struct Nand *mychip = &this->chips[from >> (this->chipshift)];
|
||||||
|
|
||||||
/* Don't allow read past end of device */
|
|
||||||
if (from >= this->totlen)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Don't allow a single read to cross a 512-byte block boundary */
|
/* Don't allow a single read to cross a 512-byte block boundary */
|
||||||
if (from + len > ((from | 0x1ff) + 1))
|
if (from + len > ((from | 0x1ff) + 1))
|
||||||
len = ((from | 0x1ff) + 1) - from;
|
len = ((from | 0x1ff) + 1) - from;
|
||||||
@@ -700,10 +697,6 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
void __iomem * docptr = this->virtadr;
|
void __iomem * docptr = this->virtadr;
|
||||||
struct Nand *mychip = &this->chips[to >> (this->chipshift)];
|
struct Nand *mychip = &this->chips[to >> (this->chipshift)];
|
||||||
|
|
||||||
/* Don't allow write past end of device */
|
|
||||||
if (to >= this->totlen)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Don't allow writes which aren't exactly one block (512 bytes) */
|
/* Don't allow writes which aren't exactly one block (512 bytes) */
|
||||||
if ((to & 0x1ff) || (len != 0x200))
|
if ((to & 0x1ff) || (len != 0x200))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -800,7 +793,6 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
printk("MTD: Error 0x%x programming at 0x%x\n", dummy, (int)to);
|
printk("MTD: Error 0x%x programming at 0x%x\n", dummy, (int)to);
|
||||||
/* Error in programming
|
/* Error in programming
|
||||||
FIXME: implement Bad Block Replacement (in nftl.c ??) */
|
FIXME: implement Bad Block Replacement (in nftl.c ??) */
|
||||||
*retlen = 0;
|
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
}
|
}
|
||||||
dummy = ReadDOC(docptr, Mplus_LastDataRead);
|
dummy = ReadDOC(docptr, Mplus_LastDataRead);
|
||||||
|
|||||||
@@ -80,14 +80,9 @@ static struct nand_ecclayout docg3_oobinfo = {
|
|||||||
.oobavail = 8,
|
.oobavail = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* struct docg3_bch - BCH engine
|
|
||||||
*/
|
|
||||||
static struct bch_control *docg3_bch;
|
|
||||||
|
|
||||||
static inline u8 doc_readb(struct docg3 *docg3, u16 reg)
|
static inline u8 doc_readb(struct docg3 *docg3, u16 reg)
|
||||||
{
|
{
|
||||||
u8 val = readb(docg3->base + reg);
|
u8 val = readb(docg3->cascade->base + reg);
|
||||||
|
|
||||||
trace_docg3_io(0, 8, reg, (int)val);
|
trace_docg3_io(0, 8, reg, (int)val);
|
||||||
return val;
|
return val;
|
||||||
@@ -95,7 +90,7 @@ static inline u8 doc_readb(struct docg3 *docg3, u16 reg)
|
|||||||
|
|
||||||
static inline u16 doc_readw(struct docg3 *docg3, u16 reg)
|
static inline u16 doc_readw(struct docg3 *docg3, u16 reg)
|
||||||
{
|
{
|
||||||
u16 val = readw(docg3->base + reg);
|
u16 val = readw(docg3->cascade->base + reg);
|
||||||
|
|
||||||
trace_docg3_io(0, 16, reg, (int)val);
|
trace_docg3_io(0, 16, reg, (int)val);
|
||||||
return val;
|
return val;
|
||||||
@@ -103,13 +98,13 @@ static inline u16 doc_readw(struct docg3 *docg3, u16 reg)
|
|||||||
|
|
||||||
static inline void doc_writeb(struct docg3 *docg3, u8 val, u16 reg)
|
static inline void doc_writeb(struct docg3 *docg3, u8 val, u16 reg)
|
||||||
{
|
{
|
||||||
writeb(val, docg3->base + reg);
|
writeb(val, docg3->cascade->base + reg);
|
||||||
trace_docg3_io(1, 8, reg, val);
|
trace_docg3_io(1, 8, reg, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void doc_writew(struct docg3 *docg3, u16 val, u16 reg)
|
static inline void doc_writew(struct docg3 *docg3, u16 val, u16 reg)
|
||||||
{
|
{
|
||||||
writew(val, docg3->base + reg);
|
writew(val, docg3->cascade->base + reg);
|
||||||
trace_docg3_io(1, 16, reg, val);
|
trace_docg3_io(1, 16, reg, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,7 +638,8 @@ static int doc_ecc_bch_fix_data(struct docg3 *docg3, void *buf, u8 *hwecc)
|
|||||||
|
|
||||||
for (i = 0; i < DOC_ECC_BCH_SIZE; i++)
|
for (i = 0; i < DOC_ECC_BCH_SIZE; i++)
|
||||||
ecc[i] = bitrev8(hwecc[i]);
|
ecc[i] = bitrev8(hwecc[i]);
|
||||||
numerrs = decode_bch(docg3_bch, NULL, DOC_ECC_BCH_COVERED_BYTES,
|
numerrs = decode_bch(docg3->cascade->bch, NULL,
|
||||||
|
DOC_ECC_BCH_COVERED_BYTES,
|
||||||
NULL, ecc, NULL, errorpos);
|
NULL, ecc, NULL, errorpos);
|
||||||
BUG_ON(numerrs == -EINVAL);
|
BUG_ON(numerrs == -EINVAL);
|
||||||
if (numerrs < 0)
|
if (numerrs < 0)
|
||||||
@@ -734,7 +730,7 @@ err:
|
|||||||
* doc_read_page_getbytes - Reads bytes from a prepared page
|
* doc_read_page_getbytes - Reads bytes from a prepared page
|
||||||
* @docg3: the device
|
* @docg3: the device
|
||||||
* @len: the number of bytes to be read (must be a multiple of 4)
|
* @len: the number of bytes to be read (must be a multiple of 4)
|
||||||
* @buf: the buffer to be filled in
|
* @buf: the buffer to be filled in (or NULL is forget bytes)
|
||||||
* @first: 1 if first time read, DOC_READADDRESS should be set
|
* @first: 1 if first time read, DOC_READADDRESS should be set
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -849,7 +845,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
|
|||||||
struct mtd_oob_ops *ops)
|
struct mtd_oob_ops *ops)
|
||||||
{
|
{
|
||||||
struct docg3 *docg3 = mtd->priv;
|
struct docg3 *docg3 = mtd->priv;
|
||||||
int block0, block1, page, ret, ofs = 0;
|
int block0, block1, page, ret, skip, ofs = 0;
|
||||||
u8 *oobbuf = ops->oobbuf;
|
u8 *oobbuf = ops->oobbuf;
|
||||||
u8 *buf = ops->datbuf;
|
u8 *buf = ops->datbuf;
|
||||||
size_t len, ooblen, nbdata, nboob;
|
size_t len, ooblen, nbdata, nboob;
|
||||||
@@ -869,34 +865,36 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
|
|||||||
|
|
||||||
doc_dbg("doc_read_oob(from=%lld, mode=%d, data=(%p:%zu), oob=(%p:%zu))\n",
|
doc_dbg("doc_read_oob(from=%lld, mode=%d, data=(%p:%zu), oob=(%p:%zu))\n",
|
||||||
from, ops->mode, buf, len, oobbuf, ooblen);
|
from, ops->mode, buf, len, oobbuf, ooblen);
|
||||||
if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % DOC_LAYOUT_OOB_SIZE) ||
|
if (ooblen % DOC_LAYOUT_OOB_SIZE)
|
||||||
(from % DOC_LAYOUT_PAGE_SIZE))
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ret = -EINVAL;
|
if (from + len > mtd->size)
|
||||||
calc_block_sector(from + len, &block0, &block1, &page, &ofs,
|
return -EINVAL;
|
||||||
docg3->reliable);
|
|
||||||
if (block1 > docg3->max_block)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
ops->oobretlen = 0;
|
ops->oobretlen = 0;
|
||||||
ops->retlen = 0;
|
ops->retlen = 0;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
skip = from % DOC_LAYOUT_PAGE_SIZE;
|
||||||
|
mutex_lock(&docg3->cascade->lock);
|
||||||
while (!ret && (len > 0 || ooblen > 0)) {
|
while (!ret && (len > 0 || ooblen > 0)) {
|
||||||
calc_block_sector(from, &block0, &block1, &page, &ofs,
|
calc_block_sector(from - skip, &block0, &block1, &page, &ofs,
|
||||||
docg3->reliable);
|
docg3->reliable);
|
||||||
nbdata = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE);
|
nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip);
|
||||||
nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE);
|
nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE);
|
||||||
ret = doc_read_page_prepare(docg3, block0, block1, page, ofs);
|
ret = doc_read_page_prepare(docg3, block0, block1, page, ofs);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err;
|
goto out;
|
||||||
ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES);
|
ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_in_read;
|
goto err_in_read;
|
||||||
ret = doc_read_page_getbytes(docg3, nbdata, buf, 1);
|
ret = doc_read_page_getbytes(docg3, skip, NULL, 1);
|
||||||
|
if (ret < skip)
|
||||||
|
goto err_in_read;
|
||||||
|
ret = doc_read_page_getbytes(docg3, nbdata, buf, 0);
|
||||||
if (ret < nbdata)
|
if (ret < nbdata)
|
||||||
goto err_in_read;
|
goto err_in_read;
|
||||||
doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE - nbdata,
|
doc_read_page_getbytes(docg3,
|
||||||
|
DOC_LAYOUT_PAGE_SIZE - nbdata - skip,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0);
|
ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0);
|
||||||
if (ret < nboob)
|
if (ret < nboob)
|
||||||
@@ -950,13 +948,15 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
|
|||||||
len -= nbdata;
|
len -= nbdata;
|
||||||
ooblen -= nboob;
|
ooblen -= nboob;
|
||||||
from += DOC_LAYOUT_PAGE_SIZE;
|
from += DOC_LAYOUT_PAGE_SIZE;
|
||||||
|
skip = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&docg3->cascade->lock);
|
||||||
return ret;
|
return ret;
|
||||||
err_in_read:
|
err_in_read:
|
||||||
doc_read_page_finish(docg3);
|
doc_read_page_finish(docg3);
|
||||||
err:
|
goto out;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1114,10 +1114,10 @@ static int doc_get_op_status(struct docg3 *docg3)
|
|||||||
*/
|
*/
|
||||||
static int doc_write_erase_wait_status(struct docg3 *docg3)
|
static int doc_write_erase_wait_status(struct docg3 *docg3)
|
||||||
{
|
{
|
||||||
int status, ret = 0;
|
int i, status, ret = 0;
|
||||||
|
|
||||||
if (!doc_is_ready(docg3))
|
for (i = 0; !doc_is_ready(docg3) && i < 5; i++)
|
||||||
usleep_range(3000, 3000);
|
msleep(20);
|
||||||
if (!doc_is_ready(docg3)) {
|
if (!doc_is_ready(docg3)) {
|
||||||
doc_dbg("Timeout reached and the chip is still not ready\n");
|
doc_dbg("Timeout reached and the chip is still not ready\n");
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
@@ -1196,18 +1196,19 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
|
|||||||
int block0, block1, page, ret, ofs = 0;
|
int block0, block1, page, ret, ofs = 0;
|
||||||
|
|
||||||
doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len);
|
doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len);
|
||||||
doc_set_device_id(docg3, docg3->device_id);
|
|
||||||
|
|
||||||
info->state = MTD_ERASE_PENDING;
|
info->state = MTD_ERASE_PENDING;
|
||||||
calc_block_sector(info->addr + info->len, &block0, &block1, &page,
|
calc_block_sector(info->addr + info->len, &block0, &block1, &page,
|
||||||
&ofs, docg3->reliable);
|
&ofs, docg3->reliable);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
if (block1 > docg3->max_block || page || ofs)
|
if (info->addr + info->len > mtd->size || page || ofs)
|
||||||
goto reset_err;
|
goto reset_err;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
calc_block_sector(info->addr, &block0, &block1, &page, &ofs,
|
calc_block_sector(info->addr, &block0, &block1, &page, &ofs,
|
||||||
docg3->reliable);
|
docg3->reliable);
|
||||||
|
mutex_lock(&docg3->cascade->lock);
|
||||||
|
doc_set_device_id(docg3, docg3->device_id);
|
||||||
doc_set_reliable_mode(docg3);
|
doc_set_reliable_mode(docg3);
|
||||||
for (len = info->len; !ret && len > 0; len -= mtd->erasesize) {
|
for (len = info->len; !ret && len > 0; len -= mtd->erasesize) {
|
||||||
info->state = MTD_ERASING;
|
info->state = MTD_ERASING;
|
||||||
@@ -1215,6 +1216,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
|
|||||||
block0 += 2;
|
block0 += 2;
|
||||||
block1 += 2;
|
block1 += 2;
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&docg3->cascade->lock);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto reset_err;
|
goto reset_err;
|
||||||
@@ -1401,7 +1403,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
|
|||||||
struct mtd_oob_ops *ops)
|
struct mtd_oob_ops *ops)
|
||||||
{
|
{
|
||||||
struct docg3 *docg3 = mtd->priv;
|
struct docg3 *docg3 = mtd->priv;
|
||||||
int block0, block1, page, ret, pofs = 0, autoecc, oobdelta;
|
int ret, autoecc, oobdelta;
|
||||||
u8 *oobbuf = ops->oobbuf;
|
u8 *oobbuf = ops->oobbuf;
|
||||||
u8 *buf = ops->datbuf;
|
u8 *buf = ops->datbuf;
|
||||||
size_t len, ooblen;
|
size_t len, ooblen;
|
||||||
@@ -1438,12 +1440,8 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
|
|||||||
if (len && ooblen &&
|
if (len && ooblen &&
|
||||||
(len / DOC_LAYOUT_PAGE_SIZE) != (ooblen / oobdelta))
|
(len / DOC_LAYOUT_PAGE_SIZE) != (ooblen / oobdelta))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
if (ofs + len > mtd->size)
|
||||||
ret = -EINVAL;
|
return -EINVAL;
|
||||||
calc_block_sector(ofs + len, &block0, &block1, &page, &pofs,
|
|
||||||
docg3->reliable);
|
|
||||||
if (block1 > docg3->max_block)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
ops->oobretlen = 0;
|
ops->oobretlen = 0;
|
||||||
ops->retlen = 0;
|
ops->retlen = 0;
|
||||||
@@ -1457,6 +1455,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
|
|||||||
if (autoecc < 0)
|
if (autoecc < 0)
|
||||||
return autoecc;
|
return autoecc;
|
||||||
|
|
||||||
|
mutex_lock(&docg3->cascade->lock);
|
||||||
while (!ret && len > 0) {
|
while (!ret && len > 0) {
|
||||||
memset(oob, 0, sizeof(oob));
|
memset(oob, 0, sizeof(oob));
|
||||||
if (ofs == docg3->oob_write_ofs)
|
if (ofs == docg3->oob_write_ofs)
|
||||||
@@ -1477,8 +1476,9 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
|
|||||||
}
|
}
|
||||||
ops->retlen += DOC_LAYOUT_PAGE_SIZE;
|
ops->retlen += DOC_LAYOUT_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
err:
|
|
||||||
doc_set_device_id(docg3, 0);
|
doc_set_device_id(docg3, 0);
|
||||||
|
mutex_unlock(&docg3->cascade->lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1535,9 +1535,11 @@ static ssize_t dps0_is_key_locked(struct device *dev,
|
|||||||
struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
|
struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
|
||||||
int dps0;
|
int dps0;
|
||||||
|
|
||||||
|
mutex_lock(&docg3->cascade->lock);
|
||||||
doc_set_device_id(docg3, docg3->device_id);
|
doc_set_device_id(docg3, docg3->device_id);
|
||||||
dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
|
dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
|
||||||
doc_set_device_id(docg3, 0);
|
doc_set_device_id(docg3, 0);
|
||||||
|
mutex_unlock(&docg3->cascade->lock);
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK));
|
return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK));
|
||||||
}
|
}
|
||||||
@@ -1548,9 +1550,11 @@ static ssize_t dps1_is_key_locked(struct device *dev,
|
|||||||
struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
|
struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
|
||||||
int dps1;
|
int dps1;
|
||||||
|
|
||||||
|
mutex_lock(&docg3->cascade->lock);
|
||||||
doc_set_device_id(docg3, docg3->device_id);
|
doc_set_device_id(docg3, docg3->device_id);
|
||||||
dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
|
dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
|
||||||
doc_set_device_id(docg3, 0);
|
doc_set_device_id(docg3, 0);
|
||||||
|
mutex_unlock(&docg3->cascade->lock);
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK));
|
return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK));
|
||||||
}
|
}
|
||||||
@@ -1565,10 +1569,12 @@ static ssize_t dps0_insert_key(struct device *dev,
|
|||||||
if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
|
if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&docg3->cascade->lock);
|
||||||
doc_set_device_id(docg3, docg3->device_id);
|
doc_set_device_id(docg3, docg3->device_id);
|
||||||
for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
|
for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
|
||||||
doc_writeb(docg3, buf[i], DOC_DPS0_KEY);
|
doc_writeb(docg3, buf[i], DOC_DPS0_KEY);
|
||||||
doc_set_device_id(docg3, 0);
|
doc_set_device_id(docg3, 0);
|
||||||
|
mutex_unlock(&docg3->cascade->lock);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1582,10 +1588,12 @@ static ssize_t dps1_insert_key(struct device *dev,
|
|||||||
if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
|
if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&docg3->cascade->lock);
|
||||||
doc_set_device_id(docg3, docg3->device_id);
|
doc_set_device_id(docg3, docg3->device_id);
|
||||||
for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
|
for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
|
||||||
doc_writeb(docg3, buf[i], DOC_DPS1_KEY);
|
doc_writeb(docg3, buf[i], DOC_DPS1_KEY);
|
||||||
doc_set_device_id(docg3, 0);
|
doc_set_device_id(docg3, 0);
|
||||||
|
mutex_unlock(&docg3->cascade->lock);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1601,13 +1609,13 @@ static struct device_attribute doc_sys_attrs[DOC_MAX_NBFLOORS][4] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int doc_register_sysfs(struct platform_device *pdev,
|
static int doc_register_sysfs(struct platform_device *pdev,
|
||||||
struct mtd_info **floors)
|
struct docg3_cascade *cascade)
|
||||||
{
|
{
|
||||||
int ret = 0, floor, i = 0;
|
int ret = 0, floor, i = 0;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
|
||||||
for (floor = 0; !ret && floor < DOC_MAX_NBFLOORS && floors[floor];
|
for (floor = 0; !ret && floor < DOC_MAX_NBFLOORS &&
|
||||||
floor++)
|
cascade->floors[floor]; floor++)
|
||||||
for (i = 0; !ret && i < 4; i++)
|
for (i = 0; !ret && i < 4; i++)
|
||||||
ret = device_create_file(dev, &doc_sys_attrs[floor][i]);
|
ret = device_create_file(dev, &doc_sys_attrs[floor][i]);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
@@ -1621,12 +1629,12 @@ static int doc_register_sysfs(struct platform_device *pdev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void doc_unregister_sysfs(struct platform_device *pdev,
|
static void doc_unregister_sysfs(struct platform_device *pdev,
|
||||||
struct mtd_info **floors)
|
struct docg3_cascade *cascade)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
int floor, i;
|
int floor, i;
|
||||||
|
|
||||||
for (floor = 0; floor < DOC_MAX_NBFLOORS && floors[floor];
|
for (floor = 0; floor < DOC_MAX_NBFLOORS && cascade->floors[floor];
|
||||||
floor++)
|
floor++)
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
device_remove_file(dev, &doc_sys_attrs[floor][i]);
|
device_remove_file(dev, &doc_sys_attrs[floor][i]);
|
||||||
@@ -1640,7 +1648,11 @@ static int dbg_flashctrl_show(struct seq_file *s, void *p)
|
|||||||
struct docg3 *docg3 = (struct docg3 *)s->private;
|
struct docg3 *docg3 = (struct docg3 *)s->private;
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
u8 fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL);
|
u8 fctrl;
|
||||||
|
|
||||||
|
mutex_lock(&docg3->cascade->lock);
|
||||||
|
fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL);
|
||||||
|
mutex_unlock(&docg3->cascade->lock);
|
||||||
|
|
||||||
pos += seq_printf(s,
|
pos += seq_printf(s,
|
||||||
"FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n",
|
"FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n",
|
||||||
@@ -1658,9 +1670,12 @@ static int dbg_asicmode_show(struct seq_file *s, void *p)
|
|||||||
{
|
{
|
||||||
struct docg3 *docg3 = (struct docg3 *)s->private;
|
struct docg3 *docg3 = (struct docg3 *)s->private;
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0, pctrl, mode;
|
||||||
int pctrl = doc_register_readb(docg3, DOC_ASICMODE);
|
|
||||||
int mode = pctrl & 0x03;
|
mutex_lock(&docg3->cascade->lock);
|
||||||
|
pctrl = doc_register_readb(docg3, DOC_ASICMODE);
|
||||||
|
mode = pctrl & 0x03;
|
||||||
|
mutex_unlock(&docg3->cascade->lock);
|
||||||
|
|
||||||
pos += seq_printf(s,
|
pos += seq_printf(s,
|
||||||
"%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (",
|
"%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (",
|
||||||
@@ -1692,7 +1707,11 @@ static int dbg_device_id_show(struct seq_file *s, void *p)
|
|||||||
{
|
{
|
||||||
struct docg3 *docg3 = (struct docg3 *)s->private;
|
struct docg3 *docg3 = (struct docg3 *)s->private;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
int id = doc_register_readb(docg3, DOC_DEVICESELECT);
|
int id;
|
||||||
|
|
||||||
|
mutex_lock(&docg3->cascade->lock);
|
||||||
|
id = doc_register_readb(docg3, DOC_DEVICESELECT);
|
||||||
|
mutex_unlock(&docg3->cascade->lock);
|
||||||
|
|
||||||
pos += seq_printf(s, "DeviceId = %d\n", id);
|
pos += seq_printf(s, "DeviceId = %d\n", id);
|
||||||
return pos;
|
return pos;
|
||||||
@@ -1705,6 +1724,7 @@ static int dbg_protection_show(struct seq_file *s, void *p)
|
|||||||
int pos = 0;
|
int pos = 0;
|
||||||
int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high;
|
int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high;
|
||||||
|
|
||||||
|
mutex_lock(&docg3->cascade->lock);
|
||||||
protect = doc_register_readb(docg3, DOC_PROTECTION);
|
protect = doc_register_readb(docg3, DOC_PROTECTION);
|
||||||
dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
|
dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
|
||||||
dps0_low = doc_register_readw(docg3, DOC_DPS0_ADDRLOW);
|
dps0_low = doc_register_readw(docg3, DOC_DPS0_ADDRLOW);
|
||||||
@@ -1712,6 +1732,7 @@ static int dbg_protection_show(struct seq_file *s, void *p)
|
|||||||
dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
|
dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
|
||||||
dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW);
|
dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW);
|
||||||
dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH);
|
dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH);
|
||||||
|
mutex_unlock(&docg3->cascade->lock);
|
||||||
|
|
||||||
pos += seq_printf(s, "Protection = 0x%02x (",
|
pos += seq_printf(s, "Protection = 0x%02x (",
|
||||||
protect);
|
protect);
|
||||||
@@ -1804,7 +1825,7 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
|
|||||||
|
|
||||||
switch (chip_id) {
|
switch (chip_id) {
|
||||||
case DOC_CHIPID_G3:
|
case DOC_CHIPID_G3:
|
||||||
mtd->name = kasprintf(GFP_KERNEL, "DiskOnChip G3 floor %d",
|
mtd->name = kasprintf(GFP_KERNEL, "docg3.%d",
|
||||||
docg3->device_id);
|
docg3->device_id);
|
||||||
docg3->max_block = 2047;
|
docg3->max_block = 2047;
|
||||||
break;
|
break;
|
||||||
@@ -1817,16 +1838,17 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
|
|||||||
mtd->erasesize = DOC_LAYOUT_BLOCK_SIZE * DOC_LAYOUT_NBPLANES;
|
mtd->erasesize = DOC_LAYOUT_BLOCK_SIZE * DOC_LAYOUT_NBPLANES;
|
||||||
if (docg3->reliable == 2)
|
if (docg3->reliable == 2)
|
||||||
mtd->erasesize /= 2;
|
mtd->erasesize /= 2;
|
||||||
mtd->writesize = DOC_LAYOUT_PAGE_SIZE;
|
mtd->writebufsize = mtd->writesize = DOC_LAYOUT_PAGE_SIZE;
|
||||||
mtd->oobsize = DOC_LAYOUT_OOB_SIZE;
|
mtd->oobsize = DOC_LAYOUT_OOB_SIZE;
|
||||||
mtd->owner = THIS_MODULE;
|
mtd->owner = THIS_MODULE;
|
||||||
mtd->erase = doc_erase;
|
mtd->_erase = doc_erase;
|
||||||
mtd->read = doc_read;
|
mtd->_read = doc_read;
|
||||||
mtd->write = doc_write;
|
mtd->_write = doc_write;
|
||||||
mtd->read_oob = doc_read_oob;
|
mtd->_read_oob = doc_read_oob;
|
||||||
mtd->write_oob = doc_write_oob;
|
mtd->_write_oob = doc_write_oob;
|
||||||
mtd->block_isbad = doc_block_isbad;
|
mtd->_block_isbad = doc_block_isbad;
|
||||||
mtd->ecclayout = &docg3_oobinfo;
|
mtd->ecclayout = &docg3_oobinfo;
|
||||||
|
mtd->ecc_strength = DOC_ECC_BCH_T;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1834,6 +1856,7 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
|
|||||||
* @base: the io space where the device is probed
|
* @base: the io space where the device is probed
|
||||||
* @floor: the floor of the probed device
|
* @floor: the floor of the probed device
|
||||||
* @dev: the device
|
* @dev: the device
|
||||||
|
* @cascade: the cascade of chips this devices will belong to
|
||||||
*
|
*
|
||||||
* Checks whether a device at the specified IO range, and floor is available.
|
* Checks whether a device at the specified IO range, and floor is available.
|
||||||
*
|
*
|
||||||
@@ -1841,8 +1864,8 @@ static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
|
|||||||
* if a memory allocation failed. If floor 0 is checked, a reset of the ASIC is
|
* if a memory allocation failed. If floor 0 is checked, a reset of the ASIC is
|
||||||
* launched.
|
* launched.
|
||||||
*/
|
*/
|
||||||
static struct mtd_info *doc_probe_device(void __iomem *base, int floor,
|
static struct mtd_info * __init
|
||||||
struct device *dev)
|
doc_probe_device(struct docg3_cascade *cascade, int floor, struct device *dev)
|
||||||
{
|
{
|
||||||
int ret, bbt_nbpages;
|
int ret, bbt_nbpages;
|
||||||
u16 chip_id, chip_id_inv;
|
u16 chip_id, chip_id_inv;
|
||||||
@@ -1865,7 +1888,7 @@ static struct mtd_info *doc_probe_device(void __iomem *base, int floor,
|
|||||||
|
|
||||||
docg3->dev = dev;
|
docg3->dev = dev;
|
||||||
docg3->device_id = floor;
|
docg3->device_id = floor;
|
||||||
docg3->base = base;
|
docg3->cascade = cascade;
|
||||||
doc_set_device_id(docg3, docg3->device_id);
|
doc_set_device_id(docg3, docg3->device_id);
|
||||||
if (!floor)
|
if (!floor)
|
||||||
doc_set_asic_mode(docg3, DOC_ASICMODE_RESET);
|
doc_set_asic_mode(docg3, DOC_ASICMODE_RESET);
|
||||||
@@ -1882,7 +1905,7 @@ static struct mtd_info *doc_probe_device(void __iomem *base, int floor,
|
|||||||
switch (chip_id) {
|
switch (chip_id) {
|
||||||
case DOC_CHIPID_G3:
|
case DOC_CHIPID_G3:
|
||||||
doc_info("Found a G3 DiskOnChip at addr %p, floor %d\n",
|
doc_info("Found a G3 DiskOnChip at addr %p, floor %d\n",
|
||||||
base, floor);
|
docg3->cascade->base, floor);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id);
|
doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id);
|
||||||
@@ -1927,10 +1950,12 @@ static void doc_release_device(struct mtd_info *mtd)
|
|||||||
static int docg3_resume(struct platform_device *pdev)
|
static int docg3_resume(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
struct docg3_cascade *cascade;
|
||||||
struct mtd_info **docg3_floors, *mtd;
|
struct mtd_info **docg3_floors, *mtd;
|
||||||
struct docg3 *docg3;
|
struct docg3 *docg3;
|
||||||
|
|
||||||
docg3_floors = platform_get_drvdata(pdev);
|
cascade = platform_get_drvdata(pdev);
|
||||||
|
docg3_floors = cascade->floors;
|
||||||
mtd = docg3_floors[0];
|
mtd = docg3_floors[0];
|
||||||
docg3 = mtd->priv;
|
docg3 = mtd->priv;
|
||||||
|
|
||||||
@@ -1952,11 +1977,13 @@ static int docg3_resume(struct platform_device *pdev)
|
|||||||
static int docg3_suspend(struct platform_device *pdev, pm_message_t state)
|
static int docg3_suspend(struct platform_device *pdev, pm_message_t state)
|
||||||
{
|
{
|
||||||
int floor, i;
|
int floor, i;
|
||||||
|
struct docg3_cascade *cascade;
|
||||||
struct mtd_info **docg3_floors, *mtd;
|
struct mtd_info **docg3_floors, *mtd;
|
||||||
struct docg3 *docg3;
|
struct docg3 *docg3;
|
||||||
u8 ctrl, pwr_down;
|
u8 ctrl, pwr_down;
|
||||||
|
|
||||||
docg3_floors = platform_get_drvdata(pdev);
|
cascade = platform_get_drvdata(pdev);
|
||||||
|
docg3_floors = cascade->floors;
|
||||||
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
|
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
|
||||||
mtd = docg3_floors[floor];
|
mtd = docg3_floors[floor];
|
||||||
if (!mtd)
|
if (!mtd)
|
||||||
@@ -2006,7 +2033,7 @@ static int __init docg3_probe(struct platform_device *pdev)
|
|||||||
struct resource *ress;
|
struct resource *ress;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
int ret, floor, found = 0;
|
int ret, floor, found = 0;
|
||||||
struct mtd_info **docg3_floors;
|
struct docg3_cascade *cascade;
|
||||||
|
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
ress = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
ress = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
@@ -2017,17 +2044,19 @@ static int __init docg3_probe(struct platform_device *pdev)
|
|||||||
base = ioremap(ress->start, DOC_IOSPACE_SIZE);
|
base = ioremap(ress->start, DOC_IOSPACE_SIZE);
|
||||||
|
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
docg3_floors = kzalloc(sizeof(*docg3_floors) * DOC_MAX_NBFLOORS,
|
cascade = kzalloc(sizeof(*cascade) * DOC_MAX_NBFLOORS,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!docg3_floors)
|
if (!cascade)
|
||||||
goto nomem1;
|
goto nomem1;
|
||||||
docg3_bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
|
cascade->base = base;
|
||||||
|
mutex_init(&cascade->lock);
|
||||||
|
cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
|
||||||
DOC_ECC_BCH_PRIMPOLY);
|
DOC_ECC_BCH_PRIMPOLY);
|
||||||
if (!docg3_bch)
|
if (!cascade->bch)
|
||||||
goto nomem2;
|
goto nomem2;
|
||||||
|
|
||||||
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
|
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
|
||||||
mtd = doc_probe_device(base, floor, dev);
|
mtd = doc_probe_device(cascade, floor, dev);
|
||||||
if (IS_ERR(mtd)) {
|
if (IS_ERR(mtd)) {
|
||||||
ret = PTR_ERR(mtd);
|
ret = PTR_ERR(mtd);
|
||||||
goto err_probe;
|
goto err_probe;
|
||||||
@@ -2038,7 +2067,7 @@ static int __init docg3_probe(struct platform_device *pdev)
|
|||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
docg3_floors[floor] = mtd;
|
cascade->floors[floor] = mtd;
|
||||||
ret = mtd_device_parse_register(mtd, part_probes, NULL, NULL,
|
ret = mtd_device_parse_register(mtd, part_probes, NULL, NULL,
|
||||||
0);
|
0);
|
||||||
if (ret)
|
if (ret)
|
||||||
@@ -2046,26 +2075,26 @@ static int __init docg3_probe(struct platform_device *pdev)
|
|||||||
found++;
|
found++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = doc_register_sysfs(pdev, docg3_floors);
|
ret = doc_register_sysfs(pdev, cascade);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_probe;
|
goto err_probe;
|
||||||
if (!found)
|
if (!found)
|
||||||
goto notfound;
|
goto notfound;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, docg3_floors);
|
platform_set_drvdata(pdev, cascade);
|
||||||
doc_dbg_register(docg3_floors[0]->priv);
|
doc_dbg_register(cascade->floors[0]->priv);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
notfound:
|
notfound:
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
dev_info(dev, "No supported DiskOnChip found\n");
|
dev_info(dev, "No supported DiskOnChip found\n");
|
||||||
err_probe:
|
err_probe:
|
||||||
free_bch(docg3_bch);
|
kfree(cascade->bch);
|
||||||
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
|
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
|
||||||
if (docg3_floors[floor])
|
if (cascade->floors[floor])
|
||||||
doc_release_device(docg3_floors[floor]);
|
doc_release_device(cascade->floors[floor]);
|
||||||
nomem2:
|
nomem2:
|
||||||
kfree(docg3_floors);
|
kfree(cascade);
|
||||||
nomem1:
|
nomem1:
|
||||||
iounmap(base);
|
iounmap(base);
|
||||||
noress:
|
noress:
|
||||||
@@ -2080,19 +2109,19 @@ noress:
|
|||||||
*/
|
*/
|
||||||
static int __exit docg3_release(struct platform_device *pdev)
|
static int __exit docg3_release(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct mtd_info **docg3_floors = platform_get_drvdata(pdev);
|
struct docg3_cascade *cascade = platform_get_drvdata(pdev);
|
||||||
struct docg3 *docg3 = docg3_floors[0]->priv;
|
struct docg3 *docg3 = cascade->floors[0]->priv;
|
||||||
void __iomem *base = docg3->base;
|
void __iomem *base = cascade->base;
|
||||||
int floor;
|
int floor;
|
||||||
|
|
||||||
doc_unregister_sysfs(pdev, docg3_floors);
|
doc_unregister_sysfs(pdev, cascade);
|
||||||
doc_dbg_unregister(docg3);
|
doc_dbg_unregister(docg3);
|
||||||
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
|
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
|
||||||
if (docg3_floors[floor])
|
if (cascade->floors[floor])
|
||||||
doc_release_device(docg3_floors[floor]);
|
doc_release_device(cascade->floors[floor]);
|
||||||
|
|
||||||
kfree(docg3_floors);
|
free_bch(docg3->cascade->bch);
|
||||||
free_bch(docg3_bch);
|
kfree(cascade);
|
||||||
iounmap(base);
|
iounmap(base);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#ifndef _MTD_DOCG3_H
|
#ifndef _MTD_DOCG3_H
|
||||||
#define _MTD_DOCG3_H
|
#define _MTD_DOCG3_H
|
||||||
|
|
||||||
|
#include <linux/mtd/mtd.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flash memory areas :
|
* Flash memory areas :
|
||||||
* - 0x0000 .. 0x07ff : IPL
|
* - 0x0000 .. 0x07ff : IPL
|
||||||
@@ -266,10 +268,24 @@
|
|||||||
*/
|
*/
|
||||||
#define DOC_LAYOUT_DPS_KEY_LENGTH 8
|
#define DOC_LAYOUT_DPS_KEY_LENGTH 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct docg3_cascade - Cascade of 1 to 4 docg3 chips
|
||||||
|
* @floors: floors (ie. one physical docg3 chip is one floor)
|
||||||
|
* @base: IO space to access all chips in the cascade
|
||||||
|
* @bch: the BCH correcting control structure
|
||||||
|
* @lock: lock to protect docg3 IO space from concurrent accesses
|
||||||
|
*/
|
||||||
|
struct docg3_cascade {
|
||||||
|
struct mtd_info *floors[DOC_MAX_NBFLOORS];
|
||||||
|
void __iomem *base;
|
||||||
|
struct bch_control *bch;
|
||||||
|
struct mutex lock;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct docg3 - DiskOnChip driver private data
|
* struct docg3 - DiskOnChip driver private data
|
||||||
* @dev: the device currently under control
|
* @dev: the device currently under control
|
||||||
* @base: mapped IO space
|
* @cascade: the cascade this device belongs to
|
||||||
* @device_id: number of the cascaded DoCG3 device (0, 1, 2 or 3)
|
* @device_id: number of the cascaded DoCG3 device (0, 1, 2 or 3)
|
||||||
* @if_cfg: if true, reads are on 16bits, else reads are on 8bits
|
* @if_cfg: if true, reads are on 16bits, else reads are on 8bits
|
||||||
|
|
||||||
@@ -287,7 +303,7 @@
|
|||||||
*/
|
*/
|
||||||
struct docg3 {
|
struct docg3 {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void __iomem *base;
|
struct docg3_cascade *cascade;
|
||||||
unsigned int device_id:4;
|
unsigned int device_id:4;
|
||||||
unsigned int if_cfg:1;
|
unsigned int if_cfg:1;
|
||||||
unsigned int reliable:2;
|
unsigned int reliable:2;
|
||||||
|
|||||||
@@ -367,9 +367,6 @@ static int flash_erase (struct mtd_info *mtd,struct erase_info *instr)
|
|||||||
printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n", __func__, instr->addr, instr->len);
|
printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n", __func__, instr->addr, instr->len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* sanity checks */
|
|
||||||
if (instr->addr + instr->len > mtd->size) return (-EINVAL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check that both start and end of the requested erase are
|
* check that both start and end of the requested erase are
|
||||||
* aligned with the erasesize at the appropriate addresses.
|
* aligned with the erasesize at the appropriate addresses.
|
||||||
@@ -440,10 +437,6 @@ static int flash_read (struct mtd_info *mtd,loff_t from,size_t len,size_t *retle
|
|||||||
printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n", __func__, (__u32)from, len);
|
printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n", __func__, (__u32)from, len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* sanity checks */
|
|
||||||
if (!len) return (0);
|
|
||||||
if (from + len > mtd->size) return (-EINVAL);
|
|
||||||
|
|
||||||
/* we always read len bytes */
|
/* we always read len bytes */
|
||||||
*retlen = len;
|
*retlen = len;
|
||||||
|
|
||||||
@@ -522,11 +515,8 @@ static int flash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen
|
|||||||
printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n", __func__, (__u32)to, len);
|
printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n", __func__, (__u32)to, len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
/* sanity checks */
|
/* sanity checks */
|
||||||
if (!len) return (0);
|
if (!len) return (0);
|
||||||
if (to + len > mtd->size) return (-EINVAL);
|
|
||||||
|
|
||||||
/* first, we write a 0xFF.... padded byte until we reach a dword boundary */
|
/* first, we write a 0xFF.... padded byte until we reach a dword boundary */
|
||||||
if (to & (BUSWIDTH - 1))
|
if (to & (BUSWIDTH - 1))
|
||||||
@@ -630,14 +620,15 @@ static int __init lart_flash_init (void)
|
|||||||
mtd.name = module_name;
|
mtd.name = module_name;
|
||||||
mtd.type = MTD_NORFLASH;
|
mtd.type = MTD_NORFLASH;
|
||||||
mtd.writesize = 1;
|
mtd.writesize = 1;
|
||||||
|
mtd.writebufsize = 4;
|
||||||
mtd.flags = MTD_CAP_NORFLASH;
|
mtd.flags = MTD_CAP_NORFLASH;
|
||||||
mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN;
|
mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN;
|
||||||
mtd.erasesize = FLASH_BLOCKSIZE_MAIN;
|
mtd.erasesize = FLASH_BLOCKSIZE_MAIN;
|
||||||
mtd.numeraseregions = ARRAY_SIZE(erase_regions);
|
mtd.numeraseregions = ARRAY_SIZE(erase_regions);
|
||||||
mtd.eraseregions = erase_regions;
|
mtd.eraseregions = erase_regions;
|
||||||
mtd.erase = flash_erase;
|
mtd._erase = flash_erase;
|
||||||
mtd.read = flash_read;
|
mtd._read = flash_read;
|
||||||
mtd.write = flash_write;
|
mtd._write = flash_write;
|
||||||
mtd.owner = THIS_MODULE;
|
mtd.owner = THIS_MODULE;
|
||||||
|
|
||||||
#ifdef LART_DEBUG
|
#ifdef LART_DEBUG
|
||||||
|
|||||||
@@ -288,9 +288,6 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||||||
__func__, (long long)instr->addr,
|
__func__, (long long)instr->addr,
|
||||||
(long long)instr->len);
|
(long long)instr->len);
|
||||||
|
|
||||||
/* sanity checks */
|
|
||||||
if (instr->addr + instr->len > flash->mtd.size)
|
|
||||||
return -EINVAL;
|
|
||||||
div_u64_rem(instr->len, mtd->erasesize, &rem);
|
div_u64_rem(instr->len, mtd->erasesize, &rem);
|
||||||
if (rem)
|
if (rem)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -349,13 +346,6 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
|
pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
|
||||||
__func__, (u32)from, len);
|
__func__, (u32)from, len);
|
||||||
|
|
||||||
/* sanity checks */
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (from + len > flash->mtd.size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
spi_message_init(&m);
|
spi_message_init(&m);
|
||||||
memset(t, 0, (sizeof t));
|
memset(t, 0, (sizeof t));
|
||||||
|
|
||||||
@@ -371,9 +361,6 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
t[1].len = len;
|
t[1].len = len;
|
||||||
spi_message_add_tail(&t[1], &m);
|
spi_message_add_tail(&t[1], &m);
|
||||||
|
|
||||||
/* Byte count starts at zero. */
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
mutex_lock(&flash->lock);
|
mutex_lock(&flash->lock);
|
||||||
|
|
||||||
/* Wait till previous write/erase is done. */
|
/* Wait till previous write/erase is done. */
|
||||||
@@ -417,15 +404,6 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
|
pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
|
||||||
__func__, (u32)to, len);
|
__func__, (u32)to, len);
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
/* sanity checks */
|
|
||||||
if (!len)
|
|
||||||
return(0);
|
|
||||||
|
|
||||||
if (to + len > flash->mtd.size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
spi_message_init(&m);
|
spi_message_init(&m);
|
||||||
memset(t, 0, (sizeof t));
|
memset(t, 0, (sizeof t));
|
||||||
|
|
||||||
@@ -509,15 +487,6 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
|
pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
|
||||||
__func__, (u32)to, len);
|
__func__, (u32)to, len);
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
/* sanity checks */
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (to + len > flash->mtd.size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
spi_message_init(&m);
|
spi_message_init(&m);
|
||||||
memset(t, 0, (sizeof t));
|
memset(t, 0, (sizeof t));
|
||||||
|
|
||||||
@@ -908,14 +877,14 @@ static int __devinit m25p_probe(struct spi_device *spi)
|
|||||||
flash->mtd.writesize = 1;
|
flash->mtd.writesize = 1;
|
||||||
flash->mtd.flags = MTD_CAP_NORFLASH;
|
flash->mtd.flags = MTD_CAP_NORFLASH;
|
||||||
flash->mtd.size = info->sector_size * info->n_sectors;
|
flash->mtd.size = info->sector_size * info->n_sectors;
|
||||||
flash->mtd.erase = m25p80_erase;
|
flash->mtd._erase = m25p80_erase;
|
||||||
flash->mtd.read = m25p80_read;
|
flash->mtd._read = m25p80_read;
|
||||||
|
|
||||||
/* sst flash chips use AAI word program */
|
/* sst flash chips use AAI word program */
|
||||||
if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST)
|
if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST)
|
||||||
flash->mtd.write = sst_write;
|
flash->mtd._write = sst_write;
|
||||||
else
|
else
|
||||||
flash->mtd.write = m25p80_write;
|
flash->mtd._write = m25p80_write;
|
||||||
|
|
||||||
/* prefer "small sector" erase if possible */
|
/* prefer "small sector" erase if possible */
|
||||||
if (info->flags & SECT_4K) {
|
if (info->flags & SECT_4K) {
|
||||||
@@ -932,6 +901,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
|
|||||||
ppdata.of_node = spi->dev.of_node;
|
ppdata.of_node = spi->dev.of_node;
|
||||||
flash->mtd.dev.parent = &spi->dev;
|
flash->mtd.dev.parent = &spi->dev;
|
||||||
flash->page_size = info->page_size;
|
flash->page_size = info->page_size;
|
||||||
|
flash->mtd.writebufsize = flash->page_size;
|
||||||
|
|
||||||
if (info->addr_width)
|
if (info->addr_width)
|
||||||
flash->addr_width = info->addr_width;
|
flash->addr_width = info->addr_width;
|
||||||
@@ -1004,21 +974,7 @@ static struct spi_driver m25p80_driver = {
|
|||||||
*/
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module_spi_driver(m25p80_driver);
|
||||||
static int __init m25p80_init(void)
|
|
||||||
{
|
|
||||||
return spi_register_driver(&m25p80_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void __exit m25p80_exit(void)
|
|
||||||
{
|
|
||||||
spi_unregister_driver(&m25p80_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module_init(m25p80_init);
|
|
||||||
module_exit(m25p80_exit);
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Mike Lavender");
|
MODULE_AUTHOR("Mike Lavender");
|
||||||
|
|||||||
@@ -59,12 +59,8 @@ static int ms02nv_read(struct mtd_info *mtd, loff_t from,
|
|||||||
{
|
{
|
||||||
struct ms02nv_private *mp = mtd->priv;
|
struct ms02nv_private *mp = mtd->priv;
|
||||||
|
|
||||||
if (from + len > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memcpy(buf, mp->uaddr + from, len);
|
memcpy(buf, mp->uaddr + from, len);
|
||||||
*retlen = len;
|
*retlen = len;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,12 +69,8 @@ static int ms02nv_write(struct mtd_info *mtd, loff_t to,
|
|||||||
{
|
{
|
||||||
struct ms02nv_private *mp = mtd->priv;
|
struct ms02nv_private *mp = mtd->priv;
|
||||||
|
|
||||||
if (to + len > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memcpy(mp->uaddr + to, buf, len);
|
memcpy(mp->uaddr + to, buf, len);
|
||||||
*retlen = len;
|
*retlen = len;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,8 +207,8 @@ static int __init ms02nv_init_one(ulong addr)
|
|||||||
mtd->size = fixsize;
|
mtd->size = fixsize;
|
||||||
mtd->name = (char *)ms02nv_name;
|
mtd->name = (char *)ms02nv_name;
|
||||||
mtd->owner = THIS_MODULE;
|
mtd->owner = THIS_MODULE;
|
||||||
mtd->read = ms02nv_read;
|
mtd->_read = ms02nv_read;
|
||||||
mtd->write = ms02nv_write;
|
mtd->_write = ms02nv_write;
|
||||||
mtd->writesize = 1;
|
mtd->writesize = 1;
|
||||||
|
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
|
|||||||
@@ -164,9 +164,6 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||||||
dev_name(&spi->dev), (long long)instr->addr,
|
dev_name(&spi->dev), (long long)instr->addr,
|
||||||
(long long)instr->len);
|
(long long)instr->len);
|
||||||
|
|
||||||
/* Sanity checks */
|
|
||||||
if (instr->addr + instr->len > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
div_u64_rem(instr->len, priv->page_size, &rem);
|
div_u64_rem(instr->len, priv->page_size, &rem);
|
||||||
if (rem)
|
if (rem)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -252,14 +249,6 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
pr_debug("%s: read 0x%x..0x%x\n", dev_name(&priv->spi->dev),
|
pr_debug("%s: read 0x%x..0x%x\n", dev_name(&priv->spi->dev),
|
||||||
(unsigned)from, (unsigned)(from + len));
|
(unsigned)from, (unsigned)(from + len));
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
/* Sanity checks */
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
if (from + len > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Calculate flash page/byte address */
|
/* Calculate flash page/byte address */
|
||||||
addr = (((unsigned)from / priv->page_size) << priv->page_offset)
|
addr = (((unsigned)from / priv->page_size) << priv->page_offset)
|
||||||
+ ((unsigned)from % priv->page_size);
|
+ ((unsigned)from % priv->page_size);
|
||||||
@@ -328,14 +317,6 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
pr_debug("%s: write 0x%x..0x%x\n",
|
pr_debug("%s: write 0x%x..0x%x\n",
|
||||||
dev_name(&spi->dev), (unsigned)to, (unsigned)(to + len));
|
dev_name(&spi->dev), (unsigned)to, (unsigned)(to + len));
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
/* Sanity checks */
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
if ((to + len) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
spi_message_init(&msg);
|
spi_message_init(&msg);
|
||||||
|
|
||||||
x[0].tx_buf = command = priv->command;
|
x[0].tx_buf = command = priv->command;
|
||||||
@@ -490,8 +471,6 @@ static ssize_t otp_read(struct spi_device *spi, unsigned base,
|
|||||||
|
|
||||||
if ((off + len) > 64)
|
if ((off + len) > 64)
|
||||||
len = 64 - off;
|
len = 64 - off;
|
||||||
if (len == 0)
|
|
||||||
return len;
|
|
||||||
|
|
||||||
spi_message_init(&m);
|
spi_message_init(&m);
|
||||||
|
|
||||||
@@ -611,16 +590,16 @@ static int dataflash_write_user_otp(struct mtd_info *mtd,
|
|||||||
|
|
||||||
static char *otp_setup(struct mtd_info *device, char revision)
|
static char *otp_setup(struct mtd_info *device, char revision)
|
||||||
{
|
{
|
||||||
device->get_fact_prot_info = dataflash_get_otp_info;
|
device->_get_fact_prot_info = dataflash_get_otp_info;
|
||||||
device->read_fact_prot_reg = dataflash_read_fact_otp;
|
device->_read_fact_prot_reg = dataflash_read_fact_otp;
|
||||||
device->get_user_prot_info = dataflash_get_otp_info;
|
device->_get_user_prot_info = dataflash_get_otp_info;
|
||||||
device->read_user_prot_reg = dataflash_read_user_otp;
|
device->_read_user_prot_reg = dataflash_read_user_otp;
|
||||||
|
|
||||||
/* rev c parts (at45db321c and at45db1281 only!) use a
|
/* rev c parts (at45db321c and at45db1281 only!) use a
|
||||||
* different write procedure; not (yet?) implemented.
|
* different write procedure; not (yet?) implemented.
|
||||||
*/
|
*/
|
||||||
if (revision > 'c')
|
if (revision > 'c')
|
||||||
device->write_user_prot_reg = dataflash_write_user_otp;
|
device->_write_user_prot_reg = dataflash_write_user_otp;
|
||||||
|
|
||||||
return ", OTP";
|
return ", OTP";
|
||||||
}
|
}
|
||||||
@@ -672,9 +651,9 @@ add_dataflash_otp(struct spi_device *spi, char *name,
|
|||||||
device->owner = THIS_MODULE;
|
device->owner = THIS_MODULE;
|
||||||
device->type = MTD_DATAFLASH;
|
device->type = MTD_DATAFLASH;
|
||||||
device->flags = MTD_WRITEABLE;
|
device->flags = MTD_WRITEABLE;
|
||||||
device->erase = dataflash_erase;
|
device->_erase = dataflash_erase;
|
||||||
device->read = dataflash_read;
|
device->_read = dataflash_read;
|
||||||
device->write = dataflash_write;
|
device->_write = dataflash_write;
|
||||||
device->priv = priv;
|
device->priv = priv;
|
||||||
|
|
||||||
device->dev.parent = &spi->dev;
|
device->dev.parent = &spi->dev;
|
||||||
@@ -946,18 +925,7 @@ static struct spi_driver dataflash_driver = {
|
|||||||
/* FIXME: investigate suspend and resume... */
|
/* FIXME: investigate suspend and resume... */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init dataflash_init(void)
|
module_spi_driver(dataflash_driver);
|
||||||
{
|
|
||||||
return spi_register_driver(&dataflash_driver);
|
|
||||||
}
|
|
||||||
module_init(dataflash_init);
|
|
||||||
|
|
||||||
static void __exit dataflash_exit(void)
|
|
||||||
{
|
|
||||||
spi_unregister_driver(&dataflash_driver);
|
|
||||||
}
|
|
||||||
module_exit(dataflash_exit);
|
|
||||||
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Andrew Victor, David Brownell");
|
MODULE_AUTHOR("Andrew Victor, David Brownell");
|
||||||
|
|||||||
@@ -34,34 +34,23 @@ static struct mtd_info *mtd_info;
|
|||||||
|
|
||||||
static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
|
static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
{
|
{
|
||||||
if (instr->addr + instr->len > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
|
memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
|
||||||
|
|
||||||
instr->state = MTD_ERASE_DONE;
|
instr->state = MTD_ERASE_DONE;
|
||||||
mtd_erase_callback(instr);
|
mtd_erase_callback(instr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
|
static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, void **virt, resource_size_t *phys)
|
size_t *retlen, void **virt, resource_size_t *phys)
|
||||||
{
|
{
|
||||||
if (from + len > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* can we return a physical address with this driver? */
|
|
||||||
if (phys)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
*virt = mtd->priv + from;
|
*virt = mtd->priv + from;
|
||||||
*retlen = len;
|
*retlen = len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
static int ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
||||||
{
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -80,11 +69,7 @@ static unsigned long ram_get_unmapped_area(struct mtd_info *mtd,
|
|||||||
static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
|
static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, u_char *buf)
|
size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
if (from + len > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memcpy(buf, mtd->priv + from, len);
|
memcpy(buf, mtd->priv + from, len);
|
||||||
|
|
||||||
*retlen = len;
|
*retlen = len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -92,11 +77,7 @@ static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
|
static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
size_t *retlen, const u_char *buf)
|
size_t *retlen, const u_char *buf)
|
||||||
{
|
{
|
||||||
if (to + len > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memcpy((char *)mtd->priv + to, buf, len);
|
memcpy((char *)mtd->priv + to, buf, len);
|
||||||
|
|
||||||
*retlen = len;
|
*retlen = len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -126,12 +107,12 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
|
|||||||
mtd->priv = mapped_address;
|
mtd->priv = mapped_address;
|
||||||
|
|
||||||
mtd->owner = THIS_MODULE;
|
mtd->owner = THIS_MODULE;
|
||||||
mtd->erase = ram_erase;
|
mtd->_erase = ram_erase;
|
||||||
mtd->point = ram_point;
|
mtd->_point = ram_point;
|
||||||
mtd->unpoint = ram_unpoint;
|
mtd->_unpoint = ram_unpoint;
|
||||||
mtd->get_unmapped_area = ram_get_unmapped_area;
|
mtd->_get_unmapped_area = ram_get_unmapped_area;
|
||||||
mtd->read = ram_read;
|
mtd->_read = ram_read;
|
||||||
mtd->write = ram_write;
|
mtd->_write = ram_write;
|
||||||
|
|
||||||
if (mtd_device_register(mtd, NULL, 0))
|
if (mtd_device_register(mtd, NULL, 0))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|||||||
@@ -33,45 +33,33 @@ struct phram_mtd_list {
|
|||||||
|
|
||||||
static LIST_HEAD(phram_list);
|
static LIST_HEAD(phram_list);
|
||||||
|
|
||||||
|
|
||||||
static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
|
static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
{
|
{
|
||||||
u_char *start = mtd->priv;
|
u_char *start = mtd->priv;
|
||||||
|
|
||||||
if (instr->addr + instr->len > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memset(start + instr->addr, 0xff, instr->len);
|
memset(start + instr->addr, 0xff, instr->len);
|
||||||
|
|
||||||
/* This'll catch a few races. Free the thing before returning :)
|
/*
|
||||||
|
* This'll catch a few races. Free the thing before returning :)
|
||||||
* I don't feel at all ashamed. This kind of thing is possible anyway
|
* I don't feel at all ashamed. This kind of thing is possible anyway
|
||||||
* with flash, but unlikely.
|
* with flash, but unlikely.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
instr->state = MTD_ERASE_DONE;
|
instr->state = MTD_ERASE_DONE;
|
||||||
|
|
||||||
mtd_erase_callback(instr);
|
mtd_erase_callback(instr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
|
static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t *retlen, void **virt, resource_size_t *phys)
|
size_t *retlen, void **virt, resource_size_t *phys)
|
||||||
{
|
{
|
||||||
if (from + len > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* can we return a physical address with this driver? */
|
|
||||||
if (phys)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
*virt = mtd->priv + from;
|
*virt = mtd->priv + from;
|
||||||
*retlen = len;
|
*retlen = len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
static int phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
||||||
{
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
|
static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
@@ -79,14 +67,7 @@ static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
{
|
{
|
||||||
u_char *start = mtd->priv;
|
u_char *start = mtd->priv;
|
||||||
|
|
||||||
if (from >= mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (len > mtd->size - from)
|
|
||||||
len = mtd->size - from;
|
|
||||||
|
|
||||||
memcpy(buf, start + from, len);
|
memcpy(buf, start + from, len);
|
||||||
|
|
||||||
*retlen = len;
|
*retlen = len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -96,20 +77,11 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
{
|
{
|
||||||
u_char *start = mtd->priv;
|
u_char *start = mtd->priv;
|
||||||
|
|
||||||
if (to >= mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (len > mtd->size - to)
|
|
||||||
len = mtd->size - to;
|
|
||||||
|
|
||||||
memcpy(start + to, buf, len);
|
memcpy(start + to, buf, len);
|
||||||
|
|
||||||
*retlen = len;
|
*retlen = len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void unregister_devices(void)
|
static void unregister_devices(void)
|
||||||
{
|
{
|
||||||
struct phram_mtd_list *this, *safe;
|
struct phram_mtd_list *this, *safe;
|
||||||
@@ -142,11 +114,11 @@ static int register_device(char *name, unsigned long start, unsigned long len)
|
|||||||
new->mtd.name = name;
|
new->mtd.name = name;
|
||||||
new->mtd.size = len;
|
new->mtd.size = len;
|
||||||
new->mtd.flags = MTD_CAP_RAM;
|
new->mtd.flags = MTD_CAP_RAM;
|
||||||
new->mtd.erase = phram_erase;
|
new->mtd._erase = phram_erase;
|
||||||
new->mtd.point = phram_point;
|
new->mtd._point = phram_point;
|
||||||
new->mtd.unpoint = phram_unpoint;
|
new->mtd._unpoint = phram_unpoint;
|
||||||
new->mtd.read = phram_read;
|
new->mtd._read = phram_read;
|
||||||
new->mtd.write = phram_write;
|
new->mtd._write = phram_write;
|
||||||
new->mtd.owner = THIS_MODULE;
|
new->mtd.owner = THIS_MODULE;
|
||||||
new->mtd.type = MTD_RAM;
|
new->mtd.type = MTD_RAM;
|
||||||
new->mtd.erasesize = PAGE_SIZE;
|
new->mtd.erasesize = PAGE_SIZE;
|
||||||
@@ -233,7 +205,17 @@ static inline void kill_final_newline(char *str)
|
|||||||
return 1; \
|
return 1; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static int phram_setup(const char *val, struct kernel_param *kp)
|
/*
|
||||||
|
* This shall contain the module parameter if any. It is of the form:
|
||||||
|
* - phram=<device>,<address>,<size> for module case
|
||||||
|
* - phram.phram=<device>,<address>,<size> for built-in case
|
||||||
|
* We leave 64 bytes for the device name, 12 for the address and 12 for the
|
||||||
|
* size.
|
||||||
|
* Example: phram.phram=rootfs,0xa0000000,512Mi
|
||||||
|
*/
|
||||||
|
static __initdata char phram_paramline[64+12+12];
|
||||||
|
|
||||||
|
static int __init phram_setup(const char *val)
|
||||||
{
|
{
|
||||||
char buf[64+12+12], *str = buf;
|
char buf[64+12+12], *str = buf;
|
||||||
char *token[3];
|
char *token[3];
|
||||||
@@ -282,12 +264,28 @@ static int phram_setup(const char *val, struct kernel_param *kp)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
module_param_call(phram, phram_setup, NULL, NULL, 000);
|
static int __init phram_param_call(const char *val, struct kernel_param *kp)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This function is always called before 'init_phram()', whether
|
||||||
|
* built-in or module.
|
||||||
|
*/
|
||||||
|
if (strlen(val) >= sizeof(phram_paramline))
|
||||||
|
return -ENOSPC;
|
||||||
|
strcpy(phram_paramline, val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
module_param_call(phram, phram_param_call, NULL, NULL, 000);
|
||||||
MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\"");
|
MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\"");
|
||||||
|
|
||||||
|
|
||||||
static int __init init_phram(void)
|
static int __init init_phram(void)
|
||||||
{
|
{
|
||||||
|
if (phram_paramline[0])
|
||||||
|
return phram_setup(phram_paramline);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,12 +94,48 @@
|
|||||||
#include <linux/ioctl.h>
|
#include <linux/ioctl.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
|
||||||
#include <linux/mtd/mtd.h>
|
#include <linux/mtd/mtd.h>
|
||||||
#include <linux/mtd/pmc551.h>
|
|
||||||
|
#define PMC551_VERSION \
|
||||||
|
"Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n"
|
||||||
|
|
||||||
|
#define PCI_VENDOR_ID_V3_SEMI 0x11b0
|
||||||
|
#define PCI_DEVICE_ID_V3_SEMI_V370PDC 0x0200
|
||||||
|
|
||||||
|
#define PMC551_PCI_MEM_MAP0 0x50
|
||||||
|
#define PMC551_PCI_MEM_MAP1 0x54
|
||||||
|
#define PMC551_PCI_MEM_MAP_MAP_ADDR_MASK 0x3ff00000
|
||||||
|
#define PMC551_PCI_MEM_MAP_APERTURE_MASK 0x000000f0
|
||||||
|
#define PMC551_PCI_MEM_MAP_REG_EN 0x00000002
|
||||||
|
#define PMC551_PCI_MEM_MAP_ENABLE 0x00000001
|
||||||
|
|
||||||
|
#define PMC551_SDRAM_MA 0x60
|
||||||
|
#define PMC551_SDRAM_CMD 0x62
|
||||||
|
#define PMC551_DRAM_CFG 0x64
|
||||||
|
#define PMC551_SYS_CTRL_REG 0x78
|
||||||
|
|
||||||
|
#define PMC551_DRAM_BLK0 0x68
|
||||||
|
#define PMC551_DRAM_BLK1 0x6c
|
||||||
|
#define PMC551_DRAM_BLK2 0x70
|
||||||
|
#define PMC551_DRAM_BLK3 0x74
|
||||||
|
#define PMC551_DRAM_BLK_GET_SIZE(x) (524288 << ((x >> 4) & 0x0f))
|
||||||
|
#define PMC551_DRAM_BLK_SET_COL_MUX(x, v) (((x) & ~0x00007000) | (((v) & 0x7) << 12))
|
||||||
|
#define PMC551_DRAM_BLK_SET_ROW_MUX(x, v) (((x) & ~0x00000f00) | (((v) & 0xf) << 8))
|
||||||
|
|
||||||
|
struct mypriv {
|
||||||
|
struct pci_dev *dev;
|
||||||
|
u_char *start;
|
||||||
|
u32 base_map0;
|
||||||
|
u32 curr_map0;
|
||||||
|
u32 asize;
|
||||||
|
struct mtd_info *nextpmc551;
|
||||||
|
};
|
||||||
|
|
||||||
static struct mtd_info *pmc551list;
|
static struct mtd_info *pmc551list;
|
||||||
|
|
||||||
|
static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
|
size_t *retlen, void **virt, resource_size_t *phys);
|
||||||
|
|
||||||
static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
|
static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
{
|
{
|
||||||
struct mypriv *priv = mtd->priv;
|
struct mypriv *priv = mtd->priv;
|
||||||
@@ -115,16 +151,6 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
end = instr->addr + instr->len - 1;
|
end = instr->addr + instr->len - 1;
|
||||||
|
|
||||||
/* Is it past the end? */
|
|
||||||
if (end > mtd->size) {
|
|
||||||
#ifdef CONFIG_MTD_PMC551_DEBUG
|
|
||||||
printk(KERN_DEBUG "pmc551_erase() out of bounds (%ld > %ld)\n",
|
|
||||||
(long)end, (long)mtd->size);
|
|
||||||
#endif
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
eoff_hi = end & ~(priv->asize - 1);
|
eoff_hi = end & ~(priv->asize - 1);
|
||||||
soff_hi = instr->addr & ~(priv->asize - 1);
|
soff_hi = instr->addr & ~(priv->asize - 1);
|
||||||
eoff_lo = end & (priv->asize - 1);
|
eoff_lo = end & (priv->asize - 1);
|
||||||
@@ -178,18 +204,6 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
printk(KERN_DEBUG "pmc551_point(%ld, %ld)\n", (long)from, (long)len);
|
printk(KERN_DEBUG "pmc551_point(%ld, %ld)\n", (long)from, (long)len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (from + len > mtd->size) {
|
|
||||||
#ifdef CONFIG_MTD_PMC551_DEBUG
|
|
||||||
printk(KERN_DEBUG "pmc551_point() out of bounds (%ld > %ld)\n",
|
|
||||||
(long)from + len, (long)mtd->size);
|
|
||||||
#endif
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* can we return a physical address with this driver? */
|
|
||||||
if (phys)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
soff_hi = from & ~(priv->asize - 1);
|
soff_hi = from & ~(priv->asize - 1);
|
||||||
soff_lo = from & (priv->asize - 1);
|
soff_lo = from & (priv->asize - 1);
|
||||||
|
|
||||||
@@ -205,11 +219,12 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
static int pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_MTD_PMC551_DEBUG
|
#ifdef CONFIG_MTD_PMC551_DEBUG
|
||||||
printk(KERN_DEBUG "pmc551_unpoint()\n");
|
printk(KERN_DEBUG "pmc551_unpoint()\n");
|
||||||
#endif
|
#endif
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
|
static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
@@ -228,16 +243,6 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
end = from + len - 1;
|
end = from + len - 1;
|
||||||
|
|
||||||
/* Is it past the end? */
|
|
||||||
if (end > mtd->size) {
|
|
||||||
#ifdef CONFIG_MTD_PMC551_DEBUG
|
|
||||||
printk(KERN_DEBUG "pmc551_read() out of bounds (%ld > %ld)\n",
|
|
||||||
(long)end, (long)mtd->size);
|
|
||||||
#endif
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
soff_hi = from & ~(priv->asize - 1);
|
soff_hi = from & ~(priv->asize - 1);
|
||||||
eoff_hi = end & ~(priv->asize - 1);
|
eoff_hi = end & ~(priv->asize - 1);
|
||||||
soff_lo = from & (priv->asize - 1);
|
soff_lo = from & (priv->asize - 1);
|
||||||
@@ -295,16 +300,6 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
end = to + len - 1;
|
end = to + len - 1;
|
||||||
/* Is it past the end? or did the u32 wrap? */
|
|
||||||
if (end > mtd->size) {
|
|
||||||
#ifdef CONFIG_MTD_PMC551_DEBUG
|
|
||||||
printk(KERN_DEBUG "pmc551_write() out of bounds (end: %ld, "
|
|
||||||
"size: %ld, to: %ld)\n", (long)end, (long)mtd->size,
|
|
||||||
(long)to);
|
|
||||||
#endif
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
soff_hi = to & ~(priv->asize - 1);
|
soff_hi = to & ~(priv->asize - 1);
|
||||||
eoff_hi = end & ~(priv->asize - 1);
|
eoff_hi = end & ~(priv->asize - 1);
|
||||||
soff_lo = to & (priv->asize - 1);
|
soff_lo = to & (priv->asize - 1);
|
||||||
@@ -358,7 +353,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
* mechanism
|
* mechanism
|
||||||
* returns the size of the memory region found.
|
* returns the size of the memory region found.
|
||||||
*/
|
*/
|
||||||
static u32 fixup_pmc551(struct pci_dev *dev)
|
static int fixup_pmc551(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_MTD_PMC551_BUGFIX
|
#ifdef CONFIG_MTD_PMC551_BUGFIX
|
||||||
u32 dram_data;
|
u32 dram_data;
|
||||||
@@ -668,7 +663,7 @@ static int __init init_pmc551(void)
|
|||||||
struct mypriv *priv;
|
struct mypriv *priv;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
struct mtd_info *mtd;
|
struct mtd_info *mtd;
|
||||||
u32 length = 0;
|
int length = 0;
|
||||||
|
|
||||||
if (msize) {
|
if (msize) {
|
||||||
msize = (1 << (ffs(msize) - 1)) << 20;
|
msize = (1 << (ffs(msize) - 1)) << 20;
|
||||||
@@ -786,11 +781,11 @@ static int __init init_pmc551(void)
|
|||||||
|
|
||||||
mtd->size = msize;
|
mtd->size = msize;
|
||||||
mtd->flags = MTD_CAP_RAM;
|
mtd->flags = MTD_CAP_RAM;
|
||||||
mtd->erase = pmc551_erase;
|
mtd->_erase = pmc551_erase;
|
||||||
mtd->read = pmc551_read;
|
mtd->_read = pmc551_read;
|
||||||
mtd->write = pmc551_write;
|
mtd->_write = pmc551_write;
|
||||||
mtd->point = pmc551_point;
|
mtd->_point = pmc551_point;
|
||||||
mtd->unpoint = pmc551_unpoint;
|
mtd->_unpoint = pmc551_unpoint;
|
||||||
mtd->type = MTD_RAM;
|
mtd->type = MTD_RAM;
|
||||||
mtd->name = "PMC551 RAM board";
|
mtd->name = "PMC551 RAM board";
|
||||||
mtd->erasesize = 0x10000;
|
mtd->erasesize = 0x10000;
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ static slram_mtd_list_t *slram_mtdlist = NULL;
|
|||||||
static int slram_erase(struct mtd_info *, struct erase_info *);
|
static int slram_erase(struct mtd_info *, struct erase_info *);
|
||||||
static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **,
|
static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **,
|
||||||
resource_size_t *);
|
resource_size_t *);
|
||||||
static void slram_unpoint(struct mtd_info *, loff_t, size_t);
|
static int slram_unpoint(struct mtd_info *, loff_t, size_t);
|
||||||
static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
|
static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
|
||||||
static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
|
static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
|
||||||
|
|
||||||
@@ -83,21 +83,13 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||||||
{
|
{
|
||||||
slram_priv_t *priv = mtd->priv;
|
slram_priv_t *priv = mtd->priv;
|
||||||
|
|
||||||
if (instr->addr + instr->len > mtd->size) {
|
|
||||||
return(-EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(priv->start + instr->addr, 0xff, instr->len);
|
memset(priv->start + instr->addr, 0xff, instr->len);
|
||||||
|
|
||||||
/* This'll catch a few races. Free the thing before returning :)
|
/* This'll catch a few races. Free the thing before returning :)
|
||||||
* I don't feel at all ashamed. This kind of thing is possible anyway
|
* I don't feel at all ashamed. This kind of thing is possible anyway
|
||||||
* with flash, but unlikely.
|
* with flash, but unlikely.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
instr->state = MTD_ERASE_DONE;
|
instr->state = MTD_ERASE_DONE;
|
||||||
|
|
||||||
mtd_erase_callback(instr);
|
mtd_erase_callback(instr);
|
||||||
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,20 +98,14 @@ static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
{
|
{
|
||||||
slram_priv_t *priv = mtd->priv;
|
slram_priv_t *priv = mtd->priv;
|
||||||
|
|
||||||
/* can we return a physical address with this driver? */
|
|
||||||
if (phys)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (from + len > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
*virt = priv->start + from;
|
*virt = priv->start + from;
|
||||||
*retlen = len;
|
*retlen = len;
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
static int slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
||||||
{
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
|
static int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
@@ -127,14 +113,7 @@ static int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
{
|
{
|
||||||
slram_priv_t *priv = mtd->priv;
|
slram_priv_t *priv = mtd->priv;
|
||||||
|
|
||||||
if (from > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (from + len > mtd->size)
|
|
||||||
len = mtd->size - from;
|
|
||||||
|
|
||||||
memcpy(buf, priv->start + from, len);
|
memcpy(buf, priv->start + from, len);
|
||||||
|
|
||||||
*retlen = len;
|
*retlen = len;
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
@@ -144,11 +123,7 @@ static int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
{
|
{
|
||||||
slram_priv_t *priv = mtd->priv;
|
slram_priv_t *priv = mtd->priv;
|
||||||
|
|
||||||
if (to + len > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memcpy(priv->start + to, buf, len);
|
memcpy(priv->start + to, buf, len);
|
||||||
|
|
||||||
*retlen = len;
|
*retlen = len;
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
@@ -199,11 +174,11 @@ static int register_device(char *name, unsigned long start, unsigned long length
|
|||||||
(*curmtd)->mtdinfo->name = name;
|
(*curmtd)->mtdinfo->name = name;
|
||||||
(*curmtd)->mtdinfo->size = length;
|
(*curmtd)->mtdinfo->size = length;
|
||||||
(*curmtd)->mtdinfo->flags = MTD_CAP_RAM;
|
(*curmtd)->mtdinfo->flags = MTD_CAP_RAM;
|
||||||
(*curmtd)->mtdinfo->erase = slram_erase;
|
(*curmtd)->mtdinfo->_erase = slram_erase;
|
||||||
(*curmtd)->mtdinfo->point = slram_point;
|
(*curmtd)->mtdinfo->_point = slram_point;
|
||||||
(*curmtd)->mtdinfo->unpoint = slram_unpoint;
|
(*curmtd)->mtdinfo->_unpoint = slram_unpoint;
|
||||||
(*curmtd)->mtdinfo->read = slram_read;
|
(*curmtd)->mtdinfo->_read = slram_read;
|
||||||
(*curmtd)->mtdinfo->write = slram_write;
|
(*curmtd)->mtdinfo->_write = slram_write;
|
||||||
(*curmtd)->mtdinfo->owner = THIS_MODULE;
|
(*curmtd)->mtdinfo->owner = THIS_MODULE;
|
||||||
(*curmtd)->mtdinfo->type = MTD_RAM;
|
(*curmtd)->mtdinfo->type = MTD_RAM;
|
||||||
(*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
|
(*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
|
||||||
|
|||||||
1147
drivers/mtd/devices/spear_smi.c
Normal file
1147
drivers/mtd/devices/spear_smi.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -175,9 +175,6 @@ static int sst25l_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
if (instr->addr + instr->len > flash->mtd.size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if ((uint32_t)instr->len % mtd->erasesize)
|
if ((uint32_t)instr->len % mtd->erasesize)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@@ -223,16 +220,6 @@ static int sst25l_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
unsigned char command[4];
|
unsigned char command[4];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Sanity checking */
|
|
||||||
if (len == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (from + len > flash->mtd.size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (retlen)
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
spi_message_init(&message);
|
spi_message_init(&message);
|
||||||
memset(&transfer, 0, sizeof(transfer));
|
memset(&transfer, 0, sizeof(transfer));
|
||||||
|
|
||||||
@@ -274,13 +261,6 @@ static int sst25l_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
int i, j, ret, bytes, copied = 0;
|
int i, j, ret, bytes, copied = 0;
|
||||||
unsigned char command[5];
|
unsigned char command[5];
|
||||||
|
|
||||||
/* Sanity checks */
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (to + len > flash->mtd.size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if ((uint32_t)to % mtd->writesize)
|
if ((uint32_t)to % mtd->writesize)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@@ -402,10 +382,11 @@ static int __devinit sst25l_probe(struct spi_device *spi)
|
|||||||
flash->mtd.flags = MTD_CAP_NORFLASH;
|
flash->mtd.flags = MTD_CAP_NORFLASH;
|
||||||
flash->mtd.erasesize = flash_info->erase_size;
|
flash->mtd.erasesize = flash_info->erase_size;
|
||||||
flash->mtd.writesize = flash_info->page_size;
|
flash->mtd.writesize = flash_info->page_size;
|
||||||
|
flash->mtd.writebufsize = flash_info->page_size;
|
||||||
flash->mtd.size = flash_info->page_size * flash_info->nr_pages;
|
flash->mtd.size = flash_info->page_size * flash_info->nr_pages;
|
||||||
flash->mtd.erase = sst25l_erase;
|
flash->mtd._erase = sst25l_erase;
|
||||||
flash->mtd.read = sst25l_read;
|
flash->mtd._read = sst25l_read;
|
||||||
flash->mtd.write = sst25l_write;
|
flash->mtd._write = sst25l_write;
|
||||||
|
|
||||||
dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name,
|
dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name,
|
||||||
(long long)flash->mtd.size >> 10);
|
(long long)flash->mtd.size >> 10);
|
||||||
@@ -418,9 +399,9 @@ static int __devinit sst25l_probe(struct spi_device *spi)
|
|||||||
flash->mtd.numeraseregions);
|
flash->mtd.numeraseregions);
|
||||||
|
|
||||||
|
|
||||||
ret = mtd_device_parse_register(&flash->mtd, NULL, 0,
|
ret = mtd_device_parse_register(&flash->mtd, NULL, NULL,
|
||||||
data ? data->parts : NULL,
|
data ? data->parts : NULL,
|
||||||
data ? data->nr_parts : 0);
|
data ? data->nr_parts : 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kfree(flash);
|
kfree(flash);
|
||||||
dev_set_drvdata(&spi->dev, NULL);
|
dev_set_drvdata(&spi->dev, NULL);
|
||||||
@@ -450,18 +431,7 @@ static struct spi_driver sst25l_driver = {
|
|||||||
.remove = __devexit_p(sst25l_remove),
|
.remove = __devexit_p(sst25l_remove),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init sst25l_init(void)
|
module_spi_driver(sst25l_driver);
|
||||||
{
|
|
||||||
return spi_register_driver(&sst25l_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit sst25l_exit(void)
|
|
||||||
{
|
|
||||||
spi_unregister_driver(&sst25l_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(sst25l_init);
|
|
||||||
module_exit(sst25l_exit);
|
|
||||||
|
|
||||||
MODULE_DESCRIPTION("MTD SPI driver for SST25L Flash chips");
|
MODULE_DESCRIPTION("MTD SPI driver for SST25L Flash chips");
|
||||||
MODULE_AUTHOR("Andre Renaud <andre@bluewatersys.com>, "
|
MODULE_AUTHOR("Andre Renaud <andre@bluewatersys.com>, "
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
|||||||
if (memcmp(mtd->name, "DiskOnChip", 10))
|
if (memcmp(mtd->name, "DiskOnChip", 10))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!mtd->block_isbad) {
|
if (!mtd->_block_isbad) {
|
||||||
printk(KERN_ERR
|
printk(KERN_ERR
|
||||||
"INFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
|
"INFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
|
||||||
"Please use the new diskonchip driver under the NAND subsystem.\n");
|
"Please use the new diskonchip driver under the NAND subsystem.\n");
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
|||||||
static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
|
||||||
static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
|
static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
|
||||||
size_t *retlen, void **mtdbuf, resource_size_t *phys);
|
size_t *retlen, void **mtdbuf, resource_size_t *phys);
|
||||||
static void lpddr_unpoint(struct mtd_info *mtd, loff_t adr, size_t len);
|
static int lpddr_unpoint(struct mtd_info *mtd, loff_t adr, size_t len);
|
||||||
static int get_chip(struct map_info *map, struct flchip *chip, int mode);
|
static int get_chip(struct map_info *map, struct flchip *chip, int mode);
|
||||||
static int chip_ready(struct map_info *map, struct flchip *chip, int mode);
|
static int chip_ready(struct map_info *map, struct flchip *chip, int mode);
|
||||||
static void put_chip(struct map_info *map, struct flchip *chip);
|
static void put_chip(struct map_info *map, struct flchip *chip);
|
||||||
@@ -63,18 +63,18 @@ struct mtd_info *lpddr_cmdset(struct map_info *map)
|
|||||||
mtd->type = MTD_NORFLASH;
|
mtd->type = MTD_NORFLASH;
|
||||||
|
|
||||||
/* Fill in the default mtd operations */
|
/* Fill in the default mtd operations */
|
||||||
mtd->read = lpddr_read;
|
mtd->_read = lpddr_read;
|
||||||
mtd->type = MTD_NORFLASH;
|
mtd->type = MTD_NORFLASH;
|
||||||
mtd->flags = MTD_CAP_NORFLASH;
|
mtd->flags = MTD_CAP_NORFLASH;
|
||||||
mtd->flags &= ~MTD_BIT_WRITEABLE;
|
mtd->flags &= ~MTD_BIT_WRITEABLE;
|
||||||
mtd->erase = lpddr_erase;
|
mtd->_erase = lpddr_erase;
|
||||||
mtd->write = lpddr_write_buffers;
|
mtd->_write = lpddr_write_buffers;
|
||||||
mtd->writev = lpddr_writev;
|
mtd->_writev = lpddr_writev;
|
||||||
mtd->lock = lpddr_lock;
|
mtd->_lock = lpddr_lock;
|
||||||
mtd->unlock = lpddr_unlock;
|
mtd->_unlock = lpddr_unlock;
|
||||||
if (map_is_linear(map)) {
|
if (map_is_linear(map)) {
|
||||||
mtd->point = lpddr_point;
|
mtd->_point = lpddr_point;
|
||||||
mtd->unpoint = lpddr_unpoint;
|
mtd->_unpoint = lpddr_unpoint;
|
||||||
}
|
}
|
||||||
mtd->size = 1 << lpddr->qinfo->DevSizeShift;
|
mtd->size = 1 << lpddr->qinfo->DevSizeShift;
|
||||||
mtd->erasesize = 1 << lpddr->qinfo->UniformBlockSizeShift;
|
mtd->erasesize = 1 << lpddr->qinfo->UniformBlockSizeShift;
|
||||||
@@ -530,14 +530,12 @@ static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
|
|||||||
struct flchip *chip = &lpddr->chips[chipnum];
|
struct flchip *chip = &lpddr->chips[chipnum];
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!map->virt || (adr + len > mtd->size))
|
if (!map->virt)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* ofs: offset within the first chip that the first read should start */
|
/* ofs: offset within the first chip that the first read should start */
|
||||||
ofs = adr - (chipnum << lpddr->chipshift);
|
ofs = adr - (chipnum << lpddr->chipshift);
|
||||||
|
|
||||||
*mtdbuf = (void *)map->virt + chip->start + ofs;
|
*mtdbuf = (void *)map->virt + chip->start + ofs;
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
unsigned long thislen;
|
unsigned long thislen;
|
||||||
@@ -575,11 +573,11 @@ static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
|
static int lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
|
||||||
{
|
{
|
||||||
struct map_info *map = mtd->priv;
|
struct map_info *map = mtd->priv;
|
||||||
struct lpddr_private *lpddr = map->fldrv_priv;
|
struct lpddr_private *lpddr = map->fldrv_priv;
|
||||||
int chipnum = adr >> lpddr->chipshift;
|
int chipnum = adr >> lpddr->chipshift, err = 0;
|
||||||
unsigned long ofs;
|
unsigned long ofs;
|
||||||
|
|
||||||
/* ofs: offset within the first chip that the first read should start */
|
/* ofs: offset within the first chip that the first read should start */
|
||||||
@@ -603,9 +601,11 @@ static void lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
|
|||||||
chip->ref_point_counter--;
|
chip->ref_point_counter--;
|
||||||
if (chip->ref_point_counter == 0)
|
if (chip->ref_point_counter == 0)
|
||||||
chip->state = FL_READY;
|
chip->state = FL_READY;
|
||||||
} else
|
} else {
|
||||||
printk(KERN_WARNING "%s: Warning: unpoint called on non"
|
printk(KERN_WARNING "%s: Warning: unpoint called on non"
|
||||||
"pointed region\n", map->name);
|
"pointed region\n", map->name);
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
put_chip(map, chip);
|
put_chip(map, chip);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
@@ -614,6 +614,8 @@ static void lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
|
|||||||
ofs = 0;
|
ofs = 0;
|
||||||
chipnum++;
|
chipnum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
|
static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
@@ -637,13 +639,11 @@ static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
|||||||
int chipnum;
|
int chipnum;
|
||||||
unsigned long ofs, vec_seek, i;
|
unsigned long ofs, vec_seek, i;
|
||||||
int wbufsize = 1 << lpddr->qinfo->BufSizeShift;
|
int wbufsize = 1 << lpddr->qinfo->BufSizeShift;
|
||||||
|
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
len += vecs[i].iov_len;
|
len += vecs[i].iov_len;
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
if (!len)
|
if (!len)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -688,9 +688,6 @@ static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||||||
ofs = instr->addr;
|
ofs = instr->addr;
|
||||||
len = instr->len;
|
len = instr->len;
|
||||||
|
|
||||||
if (ofs > mtd->size || (len + ofs) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
ret = do_erase_oneblock(mtd, ofs);
|
ret = do_erase_oneblock(mtd, ofs);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|||||||
@@ -164,8 +164,8 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev)
|
|||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtd_device_parse_register(state->mtd, part_probe_types, 0,
|
mtd_device_parse_register(state->mtd, part_probe_types, NULL,
|
||||||
pdata->parts, pdata->nr_parts);
|
pdata->parts, pdata->nr_parts);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, state);
|
platform_set_drvdata(pdev, state);
|
||||||
|
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ static int __init init_dc21285(void)
|
|||||||
|
|
||||||
dc21285_mtd->owner = THIS_MODULE;
|
dc21285_mtd->owner = THIS_MODULE;
|
||||||
|
|
||||||
mtd_device_parse_register(dc21285_mtd, probes, 0, NULL, 0);
|
mtd_device_parse_register(dc21285_mtd, probes, NULL, NULL, 0);
|
||||||
|
|
||||||
if(machine_is_ebsa285()) {
|
if(machine_is_ebsa285()) {
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -252,8 +252,8 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mtd_device_parse_register(state->mtd, part_probe_types, 0,
|
mtd_device_parse_register(state->mtd, part_probe_types, NULL,
|
||||||
pdata->parts, pdata->nr_parts);
|
pdata->parts, pdata->nr_parts);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,8 +85,8 @@ static int __init h720x_mtd_init(void)
|
|||||||
if (mymtd) {
|
if (mymtd) {
|
||||||
mymtd->owner = THIS_MODULE;
|
mymtd->owner = THIS_MODULE;
|
||||||
|
|
||||||
mtd_device_parse_register(mymtd, NULL, 0,
|
mtd_device_parse_register(mymtd, NULL, NULL,
|
||||||
h720x_partitions, NUM_PARTITIONS);
|
h720x_partitions, NUM_PARTITIONS);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ static int __init init_impa7(void)
|
|||||||
if (impa7_mtd[i]) {
|
if (impa7_mtd[i]) {
|
||||||
impa7_mtd[i]->owner = THIS_MODULE;
|
impa7_mtd[i]->owner = THIS_MODULE;
|
||||||
devicesfound++;
|
devicesfound++;
|
||||||
mtd_device_parse_register(impa7_mtd[i], NULL, 0,
|
mtd_device_parse_register(impa7_mtd[i], NULL, NULL,
|
||||||
partitions,
|
partitions,
|
||||||
ARRAY_SIZE(partitions));
|
ARRAY_SIZE(partitions));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p)
|
|||||||
{
|
{
|
||||||
/* register the flash bank */
|
/* register the flash bank */
|
||||||
/* partition the flash bank */
|
/* partition the flash bank */
|
||||||
return mtd_device_parse_register(p->info, NULL, 0, NULL, 0);
|
return mtd_device_parse_register(p->info, NULL, NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
|
static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ static int ixp2000_flash_probe(struct platform_device *dev)
|
|||||||
}
|
}
|
||||||
info->mtd->owner = THIS_MODULE;
|
info->mtd->owner = THIS_MODULE;
|
||||||
|
|
||||||
err = mtd_device_parse_register(info->mtd, probes, 0, NULL, 0);
|
err = mtd_device_parse_register(info->mtd, probes, NULL, NULL, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto Error;
|
goto Error;
|
||||||
|
|
||||||
|
|||||||
@@ -182,6 +182,9 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
|
|||||||
{
|
{
|
||||||
struct flash_platform_data *plat = dev->dev.platform_data;
|
struct flash_platform_data *plat = dev->dev.platform_data;
|
||||||
struct ixp4xx_flash_info *info;
|
struct ixp4xx_flash_info *info;
|
||||||
|
struct mtd_part_parser_data ppdata = {
|
||||||
|
.origin = dev->resource->start,
|
||||||
|
};
|
||||||
int err = -1;
|
int err = -1;
|
||||||
|
|
||||||
if (!plat)
|
if (!plat)
|
||||||
@@ -247,7 +250,7 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
|
|||||||
/* Use the fast version */
|
/* Use the fast version */
|
||||||
info->map.write = ixp4xx_write16;
|
info->map.write = ixp4xx_write16;
|
||||||
|
|
||||||
err = mtd_device_parse_register(info->mtd, probes, dev->resource->start,
|
err = mtd_device_parse_register(info->mtd, probes, &ppdata,
|
||||||
plat->parts, plat->nr_parts);
|
plat->parts, plat->nr_parts);
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_ERR "Could not parse partitions\n");
|
printk(KERN_ERR "Could not parse partitions\n");
|
||||||
|
|||||||
@@ -27,17 +27,21 @@ static struct mtd_info *mymtd;
|
|||||||
|
|
||||||
|
|
||||||
/* Is this really the vpp port? */
|
/* Is this really the vpp port? */
|
||||||
|
static DEFINE_SPINLOCK(l440gx_vpp_lock);
|
||||||
|
static int l440gx_vpp_refcnt;
|
||||||
static void l440gx_set_vpp(struct map_info *map, int vpp)
|
static void l440gx_set_vpp(struct map_info *map, int vpp)
|
||||||
{
|
{
|
||||||
unsigned long l;
|
unsigned long flags;
|
||||||
|
|
||||||
l = inl(VPP_PORT);
|
spin_lock_irqsave(&l440gx_vpp_lock, flags);
|
||||||
if (vpp) {
|
if (vpp) {
|
||||||
l |= 1;
|
if (++l440gx_vpp_refcnt == 1) /* first nested 'on' */
|
||||||
|
outl(inl(VPP_PORT) | 1, VPP_PORT);
|
||||||
} else {
|
} else {
|
||||||
l &= ~1;
|
if (--l440gx_vpp_refcnt == 0) /* last nested 'off' */
|
||||||
|
outl(inl(VPP_PORT) & ~1, VPP_PORT);
|
||||||
}
|
}
|
||||||
outl(l, VPP_PORT);
|
spin_unlock_irqrestore(&l440gx_vpp_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct map_info l440gx_map = {
|
static struct map_info l440gx_map = {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ struct ltq_mtd {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static char ltq_map_name[] = "ltq_nor";
|
static char ltq_map_name[] = "ltq_nor";
|
||||||
|
static const char *ltq_probe_types[] __devinitconst = { "cmdlinepart", NULL };
|
||||||
|
|
||||||
static map_word
|
static map_word
|
||||||
ltq_read16(struct map_info *map, unsigned long adr)
|
ltq_read16(struct map_info *map, unsigned long adr)
|
||||||
@@ -168,8 +169,9 @@ ltq_mtd_probe(struct platform_device *pdev)
|
|||||||
cfi->addr_unlock1 ^= 1;
|
cfi->addr_unlock1 ^= 1;
|
||||||
cfi->addr_unlock2 ^= 1;
|
cfi->addr_unlock2 ^= 1;
|
||||||
|
|
||||||
err = mtd_device_parse_register(ltq_mtd->mtd, NULL, 0,
|
err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types, NULL,
|
||||||
ltq_mtd_data->parts, ltq_mtd_data->nr_parts);
|
ltq_mtd_data->parts,
|
||||||
|
ltq_mtd_data->nr_parts);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&pdev->dev, "failed to add partitions\n");
|
dev_err(&pdev->dev, "failed to add partitions\n");
|
||||||
goto err_destroy;
|
goto err_destroy;
|
||||||
|
|||||||
@@ -199,8 +199,9 @@ static int __devinit latch_addr_flash_probe(struct platform_device *dev)
|
|||||||
}
|
}
|
||||||
info->mtd->owner = THIS_MODULE;
|
info->mtd->owner = THIS_MODULE;
|
||||||
|
|
||||||
mtd_device_parse_register(info->mtd, NULL, 0,
|
mtd_device_parse_register(info->mtd, NULL, NULL,
|
||||||
latch_addr_data->parts, latch_addr_data->nr_parts);
|
latch_addr_data->parts,
|
||||||
|
latch_addr_data->nr_parts);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
iounmap:
|
iounmap:
|
||||||
|
|||||||
@@ -294,13 +294,24 @@ static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *f
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static DEFINE_SPINLOCK(pcmcia_vpp_lock);
|
||||||
|
static int pcmcia_vpp_refcnt;
|
||||||
static void pcmciamtd_set_vpp(struct map_info *map, int on)
|
static void pcmciamtd_set_vpp(struct map_info *map, int on)
|
||||||
{
|
{
|
||||||
struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
|
struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
|
||||||
struct pcmcia_device *link = dev->p_dev;
|
struct pcmcia_device *link = dev->p_dev;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
pr_debug("dev = %p on = %d vpp = %d\n\n", dev, on, dev->vpp);
|
pr_debug("dev = %p on = %d vpp = %d\n\n", dev, on, dev->vpp);
|
||||||
pcmcia_fixup_vpp(link, on ? dev->vpp : 0);
|
spin_lock_irqsave(&pcmcia_vpp_lock, flags);
|
||||||
|
if (on) {
|
||||||
|
if (++pcmcia_vpp_refcnt == 1) /* first nested 'on' */
|
||||||
|
pcmcia_fixup_vpp(link, dev->vpp);
|
||||||
|
} else {
|
||||||
|
if (--pcmcia_vpp_refcnt == 0) /* last nested 'off' */
|
||||||
|
pcmcia_fixup_vpp(link, 0);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&pcmcia_vpp_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ struct physmap_flash_info {
|
|||||||
struct mtd_info *mtd[MAX_RESOURCES];
|
struct mtd_info *mtd[MAX_RESOURCES];
|
||||||
struct mtd_info *cmtd;
|
struct mtd_info *cmtd;
|
||||||
struct map_info map[MAX_RESOURCES];
|
struct map_info map[MAX_RESOURCES];
|
||||||
|
spinlock_t vpp_lock;
|
||||||
|
int vpp_refcnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int physmap_flash_remove(struct platform_device *dev)
|
static int physmap_flash_remove(struct platform_device *dev)
|
||||||
@@ -63,12 +65,26 @@ static void physmap_set_vpp(struct map_info *map, int state)
|
|||||||
{
|
{
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
struct physmap_flash_data *physmap_data;
|
struct physmap_flash_data *physmap_data;
|
||||||
|
struct physmap_flash_info *info;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
pdev = (struct platform_device *)map->map_priv_1;
|
pdev = (struct platform_device *)map->map_priv_1;
|
||||||
physmap_data = pdev->dev.platform_data;
|
physmap_data = pdev->dev.platform_data;
|
||||||
|
|
||||||
if (physmap_data->set_vpp)
|
if (!physmap_data->set_vpp)
|
||||||
physmap_data->set_vpp(pdev, state);
|
return;
|
||||||
|
|
||||||
|
info = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&info->vpp_lock, flags);
|
||||||
|
if (state) {
|
||||||
|
if (++info->vpp_refcnt == 1) /* first nested 'on' */
|
||||||
|
physmap_data->set_vpp(pdev, 1);
|
||||||
|
} else {
|
||||||
|
if (--info->vpp_refcnt == 0) /* last nested 'off' */
|
||||||
|
physmap_data->set_vpp(pdev, 0);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&info->vpp_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *rom_probe_types[] = {
|
static const char *rom_probe_types[] = {
|
||||||
@@ -172,9 +188,11 @@ static int physmap_flash_probe(struct platform_device *dev)
|
|||||||
if (err)
|
if (err)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
|
spin_lock_init(&info->vpp_lock);
|
||||||
|
|
||||||
part_types = physmap_data->part_probe_types ? : part_probe_types;
|
part_types = physmap_data->part_probe_types ? : part_probe_types;
|
||||||
|
|
||||||
mtd_device_parse_register(info->cmtd, part_types, 0,
|
mtd_device_parse_register(info->cmtd, part_types, NULL,
|
||||||
physmap_data->parts, physmap_data->nr_parts);
|
physmap_data->parts, physmap_data->nr_parts);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@@ -222,8 +222,9 @@ static int platram_probe(struct platform_device *pdev)
|
|||||||
/* check to see if there are any available partitions, or wether
|
/* check to see if there are any available partitions, or wether
|
||||||
* to add this device whole */
|
* to add this device whole */
|
||||||
|
|
||||||
err = mtd_device_parse_register(info->mtd, pdata->probes, 0,
|
err = mtd_device_parse_register(info->mtd, pdata->probes, NULL,
|
||||||
pdata->partitions, pdata->nr_partitions);
|
pdata->partitions,
|
||||||
|
pdata->nr_partitions);
|
||||||
if (!err)
|
if (!err)
|
||||||
dev_info(&pdev->dev, "registered mtd device\n");
|
dev_info(&pdev->dev, "registered mtd device\n");
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,8 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
info->mtd->owner = THIS_MODULE;
|
info->mtd->owner = THIS_MODULE;
|
||||||
|
|
||||||
mtd_device_parse_register(info->mtd, probes, 0, flash->parts, flash->nr_parts);
|
mtd_device_parse_register(info->mtd, probes, NULL, flash->parts,
|
||||||
|
flash->nr_parts);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, info);
|
platform_set_drvdata(pdev, info);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -102,8 +102,8 @@ static int rbtx4939_flash_probe(struct platform_device *dev)
|
|||||||
info->mtd->owner = THIS_MODULE;
|
info->mtd->owner = THIS_MODULE;
|
||||||
if (err)
|
if (err)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
err = mtd_device_parse_register(info->mtd, NULL, 0,
|
err = mtd_device_parse_register(info->mtd, NULL, NULL, pdata->parts,
|
||||||
pdata->parts, pdata->nr_parts);
|
pdata->nr_parts);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|||||||
@@ -36,10 +36,22 @@ struct sa_info {
|
|||||||
struct sa_subdev_info subdev[0];
|
struct sa_subdev_info subdev[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static DEFINE_SPINLOCK(sa1100_vpp_lock);
|
||||||
|
static int sa1100_vpp_refcnt;
|
||||||
static void sa1100_set_vpp(struct map_info *map, int on)
|
static void sa1100_set_vpp(struct map_info *map, int on)
|
||||||
{
|
{
|
||||||
struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
|
struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
|
||||||
subdev->plat->set_vpp(on);
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&sa1100_vpp_lock, flags);
|
||||||
|
if (on) {
|
||||||
|
if (++sa1100_vpp_refcnt == 1) /* first nested 'on' */
|
||||||
|
subdev->plat->set_vpp(1);
|
||||||
|
} else {
|
||||||
|
if (--sa1100_vpp_refcnt == 0) /* last nested 'off' */
|
||||||
|
subdev->plat->set_vpp(0);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&sa1100_vpp_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
|
static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
|
||||||
@@ -252,8 +264,8 @@ static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
|
|||||||
/*
|
/*
|
||||||
* Partition selection stuff.
|
* Partition selection stuff.
|
||||||
*/
|
*/
|
||||||
mtd_device_parse_register(info->mtd, part_probes, 0,
|
mtd_device_parse_register(info->mtd, part_probes, NULL, plat->parts,
|
||||||
plat->parts, plat->nr_parts);
|
plat->nr_parts);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, info);
|
platform_set_drvdata(pdev, info);
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|||||||
@@ -92,8 +92,8 @@ static int __init init_soleng_maps(void)
|
|||||||
mtd_device_register(eprom_mtd, NULL, 0);
|
mtd_device_register(eprom_mtd, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
mtd_device_parse_register(flash_mtd, probes, 0,
|
mtd_device_parse_register(flash_mtd, probes, NULL,
|
||||||
superh_se_partitions, NUM_PARTITIONS);
|
superh_se_partitions, NUM_PARTITIONS);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ static int __init uclinux_mtd_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mtd->owner = THIS_MODULE;
|
mtd->owner = THIS_MODULE;
|
||||||
mtd->point = uclinux_point;
|
mtd->_point = uclinux_point;
|
||||||
mtd->priv = mapp;
|
mtd->priv = mapp;
|
||||||
|
|
||||||
uclinux_ram_mtdinfo = mtd;
|
uclinux_ram_mtdinfo = mtd;
|
||||||
|
|||||||
@@ -360,9 +360,6 @@ static int vmu_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
int index = 0, retval, partition, leftover, numblocks;
|
int index = 0, retval, partition, leftover, numblocks;
|
||||||
unsigned char cx;
|
unsigned char cx;
|
||||||
|
|
||||||
if (len < 1)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
mpart = mtd->priv;
|
mpart = mtd->priv;
|
||||||
mdev = mpart->mdev;
|
mdev = mpart->mdev;
|
||||||
partition = mpart->partition;
|
partition = mpart->partition;
|
||||||
@@ -434,11 +431,6 @@ static int vmu_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
partition = mpart->partition;
|
partition = mpart->partition;
|
||||||
card = maple_get_drvdata(mdev);
|
card = maple_get_drvdata(mdev);
|
||||||
|
|
||||||
/* simple sanity checks */
|
|
||||||
if (len < 1) {
|
|
||||||
error = -EIO;
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
numblocks = card->parts[partition].numblocks;
|
numblocks = card->parts[partition].numblocks;
|
||||||
if (to + len > numblocks * card->blocklen)
|
if (to + len > numblocks * card->blocklen)
|
||||||
len = numblocks * card->blocklen - to;
|
len = numblocks * card->blocklen - to;
|
||||||
@@ -544,9 +536,9 @@ static void vmu_queryblocks(struct mapleq *mq)
|
|||||||
mtd_cur->flags = MTD_WRITEABLE|MTD_NO_ERASE;
|
mtd_cur->flags = MTD_WRITEABLE|MTD_NO_ERASE;
|
||||||
mtd_cur->size = part_cur->numblocks * card->blocklen;
|
mtd_cur->size = part_cur->numblocks * card->blocklen;
|
||||||
mtd_cur->erasesize = card->blocklen;
|
mtd_cur->erasesize = card->blocklen;
|
||||||
mtd_cur->write = vmu_flash_write;
|
mtd_cur->_write = vmu_flash_write;
|
||||||
mtd_cur->read = vmu_flash_read;
|
mtd_cur->_read = vmu_flash_read;
|
||||||
mtd_cur->sync = vmu_flash_sync;
|
mtd_cur->_sync = vmu_flash_sync;
|
||||||
mtd_cur->writesize = card->blocklen;
|
mtd_cur->writesize = card->blocklen;
|
||||||
|
|
||||||
mpart = kmalloc(sizeof(struct mdev_part), GFP_KERNEL);
|
mpart = kmalloc(sizeof(struct mdev_part), GFP_KERNEL);
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ static int __init init_sbc82xx_flash(void)
|
|||||||
nr_parts = ARRAY_SIZE(smallflash_parts);
|
nr_parts = ARRAY_SIZE(smallflash_parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
mtd_device_parse_register(sbcmtd[i], part_probes, 0,
|
mtd_device_parse_register(sbcmtd[i], part_probes, NULL,
|
||||||
defparts, nr_parts);
|
defparts, nr_parts);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
|
|||||||
ret = __get_mtd_device(dev->mtd);
|
ret = __get_mtd_device(dev->mtd);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error_release;
|
goto error_release;
|
||||||
|
dev->file_mode = mode;
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
dev->open++;
|
dev->open++;
|
||||||
|
|||||||
@@ -321,8 +321,12 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd)
|
|||||||
mutex_unlock(&mtdblk->cache_mutex);
|
mutex_unlock(&mtdblk->cache_mutex);
|
||||||
|
|
||||||
if (!--mtdblk->count) {
|
if (!--mtdblk->count) {
|
||||||
/* It was the last usage. Free the cache */
|
/*
|
||||||
mtd_sync(mbd->mtd);
|
* It was the last usage. Free the cache, but only sync if
|
||||||
|
* opened for writing.
|
||||||
|
*/
|
||||||
|
if (mbd->file_mode & FMODE_WRITE)
|
||||||
|
mtd_sync(mbd->mtd);
|
||||||
vfree(mtdblk->cache_data);
|
vfree(mtdblk->cache_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ static int mtdchar_writeoob(struct file *file, struct mtd_info *mtd,
|
|||||||
if (length > 4096)
|
if (length > 4096)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!mtd->write_oob)
|
if (!mtd->_write_oob)
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
else
|
else
|
||||||
ret = access_ok(VERIFY_READ, ptr, length) ? 0 : -EFAULT;
|
ret = access_ok(VERIFY_READ, ptr, length) ? 0 : -EFAULT;
|
||||||
@@ -576,7 +576,7 @@ static int mtdchar_write_ioctl(struct mtd_info *mtd,
|
|||||||
!access_ok(VERIFY_READ, req.usr_data, req.len) ||
|
!access_ok(VERIFY_READ, req.usr_data, req.len) ||
|
||||||
!access_ok(VERIFY_READ, req.usr_oob, req.ooblen))
|
!access_ok(VERIFY_READ, req.usr_oob, req.ooblen))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (!mtd->write_oob)
|
if (!mtd->_write_oob)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
ops.mode = req.mode;
|
ops.mode = req.mode;
|
||||||
|
|||||||
@@ -72,8 +72,6 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
int ret = 0, err;
|
int ret = 0, err;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
for (i = 0; i < concat->num_subdev; i++) {
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
struct mtd_info *subdev = concat->subdev[i];
|
||||||
size_t size, retsize;
|
size_t size, retsize;
|
||||||
@@ -126,11 +124,6 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
for (i = 0; i < concat->num_subdev; i++) {
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
struct mtd_info *subdev = concat->subdev[i];
|
||||||
size_t size, retsize;
|
size_t size, retsize;
|
||||||
@@ -145,11 +138,7 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
else
|
else
|
||||||
size = len;
|
size = len;
|
||||||
|
|
||||||
if (!(subdev->flags & MTD_WRITEABLE))
|
err = mtd_write(subdev, to, size, &retsize, buf);
|
||||||
err = -EROFS;
|
|
||||||
else
|
|
||||||
err = mtd_write(subdev, to, size, &retsize, buf);
|
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -176,19 +165,10 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
|||||||
int i;
|
int i;
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
|
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
|
|
||||||
*retlen = 0;
|
|
||||||
|
|
||||||
/* Calculate total length of data */
|
/* Calculate total length of data */
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
total_len += vecs[i].iov_len;
|
total_len += vecs[i].iov_len;
|
||||||
|
|
||||||
/* Do not allow write past end of device */
|
|
||||||
if ((to + total_len) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Check alignment */
|
/* Check alignment */
|
||||||
if (mtd->writesize > 1) {
|
if (mtd->writesize > 1) {
|
||||||
uint64_t __to = to;
|
uint64_t __to = to;
|
||||||
@@ -224,12 +204,8 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
|||||||
old_iov_len = vecs_copy[entry_high].iov_len;
|
old_iov_len = vecs_copy[entry_high].iov_len;
|
||||||
vecs_copy[entry_high].iov_len = size;
|
vecs_copy[entry_high].iov_len = size;
|
||||||
|
|
||||||
if (!(subdev->flags & MTD_WRITEABLE))
|
err = mtd_writev(subdev, &vecs_copy[entry_low],
|
||||||
err = -EROFS;
|
entry_high - entry_low + 1, to, &retsize);
|
||||||
else
|
|
||||||
err = mtd_writev(subdev, &vecs_copy[entry_low],
|
|
||||||
entry_high - entry_low + 1, to,
|
|
||||||
&retsize);
|
|
||||||
|
|
||||||
vecs_copy[entry_high].iov_len = old_iov_len - size;
|
vecs_copy[entry_high].iov_len = old_iov_len - size;
|
||||||
vecs_copy[entry_high].iov_base += size;
|
vecs_copy[entry_high].iov_base += size;
|
||||||
@@ -403,15 +379,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||||||
uint64_t length, offset = 0;
|
uint64_t length, offset = 0;
|
||||||
struct erase_info *erase;
|
struct erase_info *erase;
|
||||||
|
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
|
|
||||||
if (instr->addr > concat->mtd.size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (instr->len + instr->addr > concat->mtd.size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for proper erase block alignment of the to-be-erased area.
|
* Check for proper erase block alignment of the to-be-erased area.
|
||||||
* It is easier to do this based on the super device's erase
|
* It is easier to do this based on the super device's erase
|
||||||
@@ -459,8 +426,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
|
|
||||||
|
|
||||||
/* make a local copy of instr to avoid modifying the caller's struct */
|
/* make a local copy of instr to avoid modifying the caller's struct */
|
||||||
erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
|
erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
|
||||||
|
|
||||||
@@ -499,10 +464,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||||||
else
|
else
|
||||||
erase->len = length;
|
erase->len = length;
|
||||||
|
|
||||||
if (!(subdev->flags & MTD_WRITEABLE)) {
|
|
||||||
err = -EROFS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
length -= erase->len;
|
length -= erase->len;
|
||||||
if ((err = concat_dev_erase(subdev, erase))) {
|
if ((err = concat_dev_erase(subdev, erase))) {
|
||||||
/* sanity check: should never happen since
|
/* sanity check: should never happen since
|
||||||
@@ -538,9 +499,6 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
|||||||
struct mtd_concat *concat = CONCAT(mtd);
|
struct mtd_concat *concat = CONCAT(mtd);
|
||||||
int i, err = -EINVAL;
|
int i, err = -EINVAL;
|
||||||
|
|
||||||
if ((len + ofs) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
for (i = 0; i < concat->num_subdev; i++) {
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
struct mtd_info *subdev = concat->subdev[i];
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
@@ -575,9 +533,6 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
|||||||
struct mtd_concat *concat = CONCAT(mtd);
|
struct mtd_concat *concat = CONCAT(mtd);
|
||||||
int i, err = 0;
|
int i, err = 0;
|
||||||
|
|
||||||
if ((len + ofs) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
for (i = 0; i < concat->num_subdev; i++) {
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
struct mtd_info *subdev = concat->subdev[i];
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
@@ -650,9 +605,6 @@ static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
|||||||
if (!mtd_can_have_bb(concat->subdev[0]))
|
if (!mtd_can_have_bb(concat->subdev[0]))
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
if (ofs > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
for (i = 0; i < concat->num_subdev; i++) {
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
struct mtd_info *subdev = concat->subdev[i];
|
||||||
|
|
||||||
@@ -673,12 +625,6 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||||||
struct mtd_concat *concat = CONCAT(mtd);
|
struct mtd_concat *concat = CONCAT(mtd);
|
||||||
int i, err = -EINVAL;
|
int i, err = -EINVAL;
|
||||||
|
|
||||||
if (!mtd_can_have_bb(concat->subdev[0]))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (ofs > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
for (i = 0; i < concat->num_subdev; i++) {
|
for (i = 0; i < concat->num_subdev; i++) {
|
||||||
struct mtd_info *subdev = concat->subdev[i];
|
struct mtd_info *subdev = concat->subdev[i];
|
||||||
|
|
||||||
@@ -716,10 +662,6 @@ static unsigned long concat_get_unmapped_area(struct mtd_info *mtd,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we've found the subdev over which the mapping will reside */
|
|
||||||
if (offset + len > subdev->size)
|
|
||||||
return (unsigned long) -EINVAL;
|
|
||||||
|
|
||||||
return mtd_get_unmapped_area(subdev, len, offset, flags);
|
return mtd_get_unmapped_area(subdev, len, offset, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -777,16 +719,16 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
|||||||
concat->mtd.subpage_sft = subdev[0]->subpage_sft;
|
concat->mtd.subpage_sft = subdev[0]->subpage_sft;
|
||||||
concat->mtd.oobsize = subdev[0]->oobsize;
|
concat->mtd.oobsize = subdev[0]->oobsize;
|
||||||
concat->mtd.oobavail = subdev[0]->oobavail;
|
concat->mtd.oobavail = subdev[0]->oobavail;
|
||||||
if (subdev[0]->writev)
|
if (subdev[0]->_writev)
|
||||||
concat->mtd.writev = concat_writev;
|
concat->mtd._writev = concat_writev;
|
||||||
if (subdev[0]->read_oob)
|
if (subdev[0]->_read_oob)
|
||||||
concat->mtd.read_oob = concat_read_oob;
|
concat->mtd._read_oob = concat_read_oob;
|
||||||
if (subdev[0]->write_oob)
|
if (subdev[0]->_write_oob)
|
||||||
concat->mtd.write_oob = concat_write_oob;
|
concat->mtd._write_oob = concat_write_oob;
|
||||||
if (subdev[0]->block_isbad)
|
if (subdev[0]->_block_isbad)
|
||||||
concat->mtd.block_isbad = concat_block_isbad;
|
concat->mtd._block_isbad = concat_block_isbad;
|
||||||
if (subdev[0]->block_markbad)
|
if (subdev[0]->_block_markbad)
|
||||||
concat->mtd.block_markbad = concat_block_markbad;
|
concat->mtd._block_markbad = concat_block_markbad;
|
||||||
|
|
||||||
concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
|
concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
|
||||||
|
|
||||||
@@ -833,8 +775,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
|||||||
if (concat->mtd.writesize != subdev[i]->writesize ||
|
if (concat->mtd.writesize != subdev[i]->writesize ||
|
||||||
concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
|
concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
|
||||||
concat->mtd.oobsize != subdev[i]->oobsize ||
|
concat->mtd.oobsize != subdev[i]->oobsize ||
|
||||||
!concat->mtd.read_oob != !subdev[i]->read_oob ||
|
!concat->mtd._read_oob != !subdev[i]->_read_oob ||
|
||||||
!concat->mtd.write_oob != !subdev[i]->write_oob) {
|
!concat->mtd._write_oob != !subdev[i]->_write_oob) {
|
||||||
kfree(concat);
|
kfree(concat);
|
||||||
printk("Incompatible OOB or ECC data on \"%s\"\n",
|
printk("Incompatible OOB or ECC data on \"%s\"\n",
|
||||||
subdev[i]->name);
|
subdev[i]->name);
|
||||||
@@ -849,15 +791,15 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
|||||||
concat->num_subdev = num_devs;
|
concat->num_subdev = num_devs;
|
||||||
concat->mtd.name = name;
|
concat->mtd.name = name;
|
||||||
|
|
||||||
concat->mtd.erase = concat_erase;
|
concat->mtd._erase = concat_erase;
|
||||||
concat->mtd.read = concat_read;
|
concat->mtd._read = concat_read;
|
||||||
concat->mtd.write = concat_write;
|
concat->mtd._write = concat_write;
|
||||||
concat->mtd.sync = concat_sync;
|
concat->mtd._sync = concat_sync;
|
||||||
concat->mtd.lock = concat_lock;
|
concat->mtd._lock = concat_lock;
|
||||||
concat->mtd.unlock = concat_unlock;
|
concat->mtd._unlock = concat_unlock;
|
||||||
concat->mtd.suspend = concat_suspend;
|
concat->mtd._suspend = concat_suspend;
|
||||||
concat->mtd.resume = concat_resume;
|
concat->mtd._resume = concat_resume;
|
||||||
concat->mtd.get_unmapped_area = concat_get_unmapped_area;
|
concat->mtd._get_unmapped_area = concat_get_unmapped_area;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Combine the erase block size info of the subdevices:
|
* Combine the erase block size info of the subdevices:
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ static LIST_HEAD(mtd_notifiers);
|
|||||||
*/
|
*/
|
||||||
static void mtd_release(struct device *dev)
|
static void mtd_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct mtd_info *mtd = dev_get_drvdata(dev);
|
struct mtd_info __maybe_unused *mtd = dev_get_drvdata(dev);
|
||||||
dev_t index = MTD_DEVT(mtd->index);
|
dev_t index = MTD_DEVT(mtd->index);
|
||||||
|
|
||||||
/* remove /dev/mtdXro node if needed */
|
/* remove /dev/mtdXro node if needed */
|
||||||
@@ -126,7 +126,7 @@ static int mtd_cls_resume(struct device *dev)
|
|||||||
{
|
{
|
||||||
struct mtd_info *mtd = dev_get_drvdata(dev);
|
struct mtd_info *mtd = dev_get_drvdata(dev);
|
||||||
|
|
||||||
if (mtd && mtd->resume)
|
if (mtd)
|
||||||
mtd_resume(mtd);
|
mtd_resume(mtd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -610,8 +610,8 @@ int __get_mtd_device(struct mtd_info *mtd)
|
|||||||
if (!try_module_get(mtd->owner))
|
if (!try_module_get(mtd->owner))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (mtd->get_device) {
|
if (mtd->_get_device) {
|
||||||
err = mtd->get_device(mtd);
|
err = mtd->_get_device(mtd);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
module_put(mtd->owner);
|
module_put(mtd->owner);
|
||||||
@@ -675,13 +675,266 @@ void __put_mtd_device(struct mtd_info *mtd)
|
|||||||
--mtd->usecount;
|
--mtd->usecount;
|
||||||
BUG_ON(mtd->usecount < 0);
|
BUG_ON(mtd->usecount < 0);
|
||||||
|
|
||||||
if (mtd->put_device)
|
if (mtd->_put_device)
|
||||||
mtd->put_device(mtd);
|
mtd->_put_device(mtd);
|
||||||
|
|
||||||
module_put(mtd->owner);
|
module_put(mtd->owner);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(__put_mtd_device);
|
EXPORT_SYMBOL_GPL(__put_mtd_device);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Erase is an asynchronous operation. Device drivers are supposed
|
||||||
|
* to call instr->callback() whenever the operation completes, even
|
||||||
|
* if it completes with a failure.
|
||||||
|
* Callers are supposed to pass a callback function and wait for it
|
||||||
|
* to be called before writing to the block.
|
||||||
|
*/
|
||||||
|
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
|
{
|
||||||
|
if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!(mtd->flags & MTD_WRITEABLE))
|
||||||
|
return -EROFS;
|
||||||
|
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
|
||||||
|
if (!instr->len) {
|
||||||
|
instr->state = MTD_ERASE_DONE;
|
||||||
|
mtd_erase_callback(instr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return mtd->_erase(mtd, instr);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_erase);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This stuff for eXecute-In-Place. phys is optional and may be set to NULL.
|
||||||
|
*/
|
||||||
|
int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||||
|
void **virt, resource_size_t *phys)
|
||||||
|
{
|
||||||
|
*retlen = 0;
|
||||||
|
*virt = NULL;
|
||||||
|
if (phys)
|
||||||
|
*phys = 0;
|
||||||
|
if (!mtd->_point)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (from < 0 || from > mtd->size || len > mtd->size - from)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_point(mtd, from, len, retlen, virt, phys);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_point);
|
||||||
|
|
||||||
|
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
|
||||||
|
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)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_unpoint(mtd, from, len);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_unpoint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allow NOMMU mmap() to directly map the device (if not NULL)
|
||||||
|
* - return the address to which the offset maps
|
||||||
|
* - return -ENOSYS to indicate refusal to do the mapping
|
||||||
|
*/
|
||||||
|
unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len,
|
||||||
|
unsigned long offset, unsigned long flags)
|
||||||
|
{
|
||||||
|
if (!mtd->_get_unmapped_area)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (offset > mtd->size || len > mtd->size - offset)
|
||||||
|
return -EINVAL;
|
||||||
|
return mtd->_get_unmapped_area(mtd, len, offset, flags);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_get_unmapped_area);
|
||||||
|
|
||||||
|
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||||
|
u_char *buf)
|
||||||
|
{
|
||||||
|
*retlen = 0;
|
||||||
|
if (from < 0 || from > mtd->size || len > mtd->size - from)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_read(mtd, from, len, retlen, buf);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_read);
|
||||||
|
|
||||||
|
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)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE))
|
||||||
|
return -EROFS;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_write(mtd, to, len, retlen, buf);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_write);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In blackbox flight recorder like scenarios we want to make successful writes
|
||||||
|
* in interrupt context. panic_write() is only intended to be called when its
|
||||||
|
* known the kernel is about to panic and we need the write to succeed. Since
|
||||||
|
* the kernel is not going to be running for much longer, this function can
|
||||||
|
* break locks and delay to ensure the write succeeds (but not sleep).
|
||||||
|
*/
|
||||||
|
int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||||
|
const u_char *buf)
|
||||||
|
{
|
||||||
|
*retlen = 0;
|
||||||
|
if (!mtd->_panic_write)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (to < 0 || to > mtd->size || len > mtd->size - to)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!(mtd->flags & MTD_WRITEABLE))
|
||||||
|
return -EROFS;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_panic_write(mtd, to, len, retlen, buf);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_panic_write);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Method to access the protection register area, present in some flash
|
||||||
|
* devices. The user data is one time programmable but the factory data is read
|
||||||
|
* only.
|
||||||
|
*/
|
||||||
|
int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
if (!mtd->_get_fact_prot_info)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_get_fact_prot_info(mtd, buf, len);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_get_fact_prot_info);
|
||||||
|
|
||||||
|
int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
|
size_t *retlen, u_char *buf)
|
||||||
|
{
|
||||||
|
*retlen = 0;
|
||||||
|
if (!mtd->_read_fact_prot_reg)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_read_fact_prot_reg(mtd, from, len, retlen, buf);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_read_fact_prot_reg);
|
||||||
|
|
||||||
|
int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
if (!mtd->_get_user_prot_info)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_get_user_prot_info(mtd, buf, len);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_get_user_prot_info);
|
||||||
|
|
||||||
|
int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
|
size_t *retlen, u_char *buf)
|
||||||
|
{
|
||||||
|
*retlen = 0;
|
||||||
|
if (!mtd->_read_user_prot_reg)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_read_user_prot_reg(mtd, from, len, retlen, buf);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_read_user_prot_reg);
|
||||||
|
|
||||||
|
int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
|
size_t *retlen, u_char *buf)
|
||||||
|
{
|
||||||
|
*retlen = 0;
|
||||||
|
if (!mtd->_write_user_prot_reg)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_write_user_prot_reg);
|
||||||
|
|
||||||
|
int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len)
|
||||||
|
{
|
||||||
|
if (!mtd->_lock_user_prot_reg)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_lock_user_prot_reg(mtd, from, len);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_lock_user_prot_reg);
|
||||||
|
|
||||||
|
/* Chip-supported device locking */
|
||||||
|
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)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_lock(mtd, ofs, len);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_lock);
|
||||||
|
|
||||||
|
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)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_unlock(mtd, ofs, len);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_unlock);
|
||||||
|
|
||||||
|
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)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
return mtd->_is_locked(mtd, ofs, len);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_is_locked);
|
||||||
|
|
||||||
|
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
|
{
|
||||||
|
if (!mtd->_block_isbad)
|
||||||
|
return 0;
|
||||||
|
if (ofs < 0 || ofs > mtd->size)
|
||||||
|
return -EINVAL;
|
||||||
|
return mtd->_block_isbad(mtd, ofs);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_block_isbad);
|
||||||
|
|
||||||
|
int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
|
{
|
||||||
|
if (!mtd->_block_markbad)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (ofs < 0 || ofs > mtd->size)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!(mtd->flags & MTD_WRITEABLE))
|
||||||
|
return -EROFS;
|
||||||
|
return mtd->_block_markbad(mtd, ofs);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_block_markbad);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* default_mtd_writev - the default writev method
|
* default_mtd_writev - the default writev method
|
||||||
* @mtd: mtd device description object pointer
|
* @mtd: mtd device description object pointer
|
||||||
@@ -729,9 +982,11 @@ int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
|||||||
unsigned long count, loff_t to, size_t *retlen)
|
unsigned long count, loff_t to, size_t *retlen)
|
||||||
{
|
{
|
||||||
*retlen = 0;
|
*retlen = 0;
|
||||||
if (!mtd->writev)
|
if (!(mtd->flags & MTD_WRITEABLE))
|
||||||
|
return -EROFS;
|
||||||
|
if (!mtd->_writev)
|
||||||
return default_mtd_writev(mtd, vecs, count, to, retlen);
|
return default_mtd_writev(mtd, vecs, count, to, retlen);
|
||||||
return mtd->writev(mtd, vecs, count, to, retlen);
|
return mtd->_writev(mtd, vecs, count, to, retlen);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mtd_writev);
|
EXPORT_SYMBOL_GPL(mtd_writev);
|
||||||
|
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ static void mtdoops_workfunc_erase(struct work_struct *work)
|
|||||||
cxt->nextpage = 0;
|
cxt->nextpage = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (mtd_can_have_bb(mtd)) {
|
while (1) {
|
||||||
ret = mtd_block_isbad(mtd, cxt->nextpage * record_size);
|
ret = mtd_block_isbad(mtd, cxt->nextpage * record_size);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
break;
|
break;
|
||||||
@@ -199,9 +199,9 @@ badblock:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mtd_can_have_bb(mtd) && ret == -EIO) {
|
if (ret == -EIO) {
|
||||||
ret = mtd_block_markbad(mtd, cxt->nextpage * record_size);
|
ret = mtd_block_markbad(mtd, cxt->nextpage * record_size);
|
||||||
if (ret < 0) {
|
if (ret < 0 && ret != -EOPNOTSUPP) {
|
||||||
printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n");
|
printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -257,8 +257,7 @@ static void find_next_position(struct mtdoops_context *cxt)
|
|||||||
size_t retlen;
|
size_t retlen;
|
||||||
|
|
||||||
for (page = 0; page < cxt->oops_pages; page++) {
|
for (page = 0; page < cxt->oops_pages; page++) {
|
||||||
if (mtd_can_have_bb(mtd) &&
|
if (mtd_block_isbad(mtd, page * record_size))
|
||||||
mtd_block_isbad(mtd, page * record_size))
|
|
||||||
continue;
|
continue;
|
||||||
/* Assume the page is used */
|
/* Assume the page is used */
|
||||||
mark_page_used(cxt, page);
|
mark_page_used(cxt, page);
|
||||||
|
|||||||
@@ -65,12 +65,8 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
int res;
|
int res;
|
||||||
|
|
||||||
stats = part->master->ecc_stats;
|
stats = part->master->ecc_stats;
|
||||||
|
res = part->master->_read(part->master, from + part->offset, len,
|
||||||
if (from >= mtd->size)
|
retlen, buf);
|
||||||
len = 0;
|
|
||||||
else if (from + len > mtd->size)
|
|
||||||
len = mtd->size - from;
|
|
||||||
res = mtd_read(part->master, from + part->offset, len, retlen, buf);
|
|
||||||
if (unlikely(res)) {
|
if (unlikely(res)) {
|
||||||
if (mtd_is_bitflip(res))
|
if (mtd_is_bitflip(res))
|
||||||
mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
|
mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
|
||||||
@@ -84,19 +80,16 @@ static int part_point(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
size_t *retlen, void **virt, resource_size_t *phys)
|
size_t *retlen, void **virt, resource_size_t *phys)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if (from >= mtd->size)
|
|
||||||
len = 0;
|
return part->master->_point(part->master, from + part->offset, len,
|
||||||
else if (from + len > mtd->size)
|
retlen, virt, phys);
|
||||||
len = mtd->size - from;
|
|
||||||
return mtd_point(part->master, from + part->offset, len, retlen,
|
|
||||||
virt, phys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
static int part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
|
|
||||||
mtd_unpoint(part->master, from + part->offset, len);
|
return part->master->_unpoint(part->master, from + part->offset, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
|
static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
|
||||||
@@ -107,7 +100,8 @@ static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
|
|||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
|
|
||||||
offset += part->offset;
|
offset += part->offset;
|
||||||
return mtd_get_unmapped_area(part->master, len, offset, flags);
|
return part->master->_get_unmapped_area(part->master, len, offset,
|
||||||
|
flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_read_oob(struct mtd_info *mtd, loff_t from,
|
static int part_read_oob(struct mtd_info *mtd, loff_t from,
|
||||||
@@ -138,7 +132,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = mtd_read_oob(part->master, from + part->offset, ops);
|
res = part->master->_read_oob(part->master, from + part->offset, ops);
|
||||||
if (unlikely(res)) {
|
if (unlikely(res)) {
|
||||||
if (mtd_is_bitflip(res))
|
if (mtd_is_bitflip(res))
|
||||||
mtd->ecc_stats.corrected++;
|
mtd->ecc_stats.corrected++;
|
||||||
@@ -152,55 +146,46 @@ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
|||||||
size_t len, size_t *retlen, u_char *buf)
|
size_t len, size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return mtd_read_user_prot_reg(part->master, from, len, retlen, buf);
|
return part->master->_read_user_prot_reg(part->master, from, len,
|
||||||
|
retlen, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_get_user_prot_info(struct mtd_info *mtd,
|
static int part_get_user_prot_info(struct mtd_info *mtd,
|
||||||
struct otp_info *buf, size_t len)
|
struct otp_info *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return mtd_get_user_prot_info(part->master, buf, len);
|
return part->master->_get_user_prot_info(part->master, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
|
static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||||
size_t len, size_t *retlen, u_char *buf)
|
size_t len, size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return mtd_read_fact_prot_reg(part->master, from, len, retlen, buf);
|
return part->master->_read_fact_prot_reg(part->master, from, len,
|
||||||
|
retlen, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return mtd_get_fact_prot_info(part->master, buf, len);
|
return part->master->_get_fact_prot_info(part->master, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
|
static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
size_t *retlen, const u_char *buf)
|
size_t *retlen, const u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
return part->master->_write(part->master, to + part->offset, len,
|
||||||
return -EROFS;
|
retlen, buf);
|
||||||
if (to >= mtd->size)
|
|
||||||
len = 0;
|
|
||||||
else if (to + len > mtd->size)
|
|
||||||
len = mtd->size - to;
|
|
||||||
return mtd_write(part->master, to + part->offset, len, retlen, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
|
static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
size_t *retlen, const u_char *buf)
|
size_t *retlen, const u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
return part->master->_panic_write(part->master, to + part->offset, len,
|
||||||
return -EROFS;
|
retlen, buf);
|
||||||
if (to >= mtd->size)
|
|
||||||
len = 0;
|
|
||||||
else if (to + len > mtd->size)
|
|
||||||
len = mtd->size - to;
|
|
||||||
return mtd_panic_write(part->master, to + part->offset, len, retlen,
|
|
||||||
buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_write_oob(struct mtd_info *mtd, loff_t to,
|
static int part_write_oob(struct mtd_info *mtd, loff_t to,
|
||||||
@@ -208,50 +193,43 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to,
|
|||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
|
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
|
|
||||||
if (to >= mtd->size)
|
if (to >= mtd->size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (ops->datbuf && to + ops->len > mtd->size)
|
if (ops->datbuf && to + ops->len > mtd->size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return mtd_write_oob(part->master, to + part->offset, ops);
|
return part->master->_write_oob(part->master, to + part->offset, ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||||
size_t len, size_t *retlen, u_char *buf)
|
size_t len, size_t *retlen, u_char *buf)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return mtd_write_user_prot_reg(part->master, from, len, retlen, buf);
|
return part->master->_write_user_prot_reg(part->master, from, len,
|
||||||
|
retlen, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return mtd_lock_user_prot_reg(part->master, from, len);
|
return part->master->_lock_user_prot_reg(part->master, from, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
||||||
unsigned long count, loff_t to, size_t *retlen)
|
unsigned long count, loff_t to, size_t *retlen)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
return part->master->_writev(part->master, vecs, count,
|
||||||
return -EROFS;
|
to + part->offset, retlen);
|
||||||
return mtd_writev(part->master, vecs, count, to + part->offset,
|
|
||||||
retlen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
|
static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
int ret;
|
int ret;
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
if (instr->addr >= mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
instr->addr += part->offset;
|
instr->addr += part->offset;
|
||||||
ret = mtd_erase(part->master, instr);
|
ret = part->master->_erase(part->master, instr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
||||||
instr->fail_addr -= part->offset;
|
instr->fail_addr -= part->offset;
|
||||||
@@ -262,7 +240,7 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||||||
|
|
||||||
void mtd_erase_callback(struct erase_info *instr)
|
void mtd_erase_callback(struct erase_info *instr)
|
||||||
{
|
{
|
||||||
if (instr->mtd->erase == part_erase) {
|
if (instr->mtd->_erase == part_erase) {
|
||||||
struct mtd_part *part = PART(instr->mtd);
|
struct mtd_part *part = PART(instr->mtd);
|
||||||
|
|
||||||
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
||||||
@@ -277,52 +255,44 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback);
|
|||||||
static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if ((len + ofs) > mtd->size)
|
return part->master->_lock(part->master, ofs + part->offset, len);
|
||||||
return -EINVAL;
|
|
||||||
return mtd_lock(part->master, ofs + part->offset, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if ((len + ofs) > mtd->size)
|
return part->master->_unlock(part->master, ofs + part->offset, len);
|
||||||
return -EINVAL;
|
|
||||||
return mtd_unlock(part->master, ofs + part->offset, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if ((len + ofs) > mtd->size)
|
return part->master->_is_locked(part->master, ofs + part->offset, len);
|
||||||
return -EINVAL;
|
|
||||||
return mtd_is_locked(part->master, ofs + part->offset, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void part_sync(struct mtd_info *mtd)
|
static void part_sync(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
mtd_sync(part->master);
|
part->master->_sync(part->master);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_suspend(struct mtd_info *mtd)
|
static int part_suspend(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
return mtd_suspend(part->master);
|
return part->master->_suspend(part->master);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void part_resume(struct mtd_info *mtd)
|
static void part_resume(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
mtd_resume(part->master);
|
part->master->_resume(part->master);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
{
|
{
|
||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
if (ofs >= mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
ofs += part->offset;
|
ofs += part->offset;
|
||||||
return mtd_block_isbad(part->master, ofs);
|
return part->master->_block_isbad(part->master, ofs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
@@ -330,12 +300,8 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||||||
struct mtd_part *part = PART(mtd);
|
struct mtd_part *part = PART(mtd);
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (!(mtd->flags & MTD_WRITEABLE))
|
|
||||||
return -EROFS;
|
|
||||||
if (ofs >= mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
ofs += part->offset;
|
ofs += part->offset;
|
||||||
res = mtd_block_markbad(part->master, ofs);
|
res = part->master->_block_markbad(part->master, ofs);
|
||||||
if (!res)
|
if (!res)
|
||||||
mtd->ecc_stats.badblocks++;
|
mtd->ecc_stats.badblocks++;
|
||||||
return res;
|
return res;
|
||||||
@@ -410,54 +376,55 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
|
|||||||
*/
|
*/
|
||||||
slave->mtd.dev.parent = master->dev.parent;
|
slave->mtd.dev.parent = master->dev.parent;
|
||||||
|
|
||||||
slave->mtd.read = part_read;
|
slave->mtd._read = part_read;
|
||||||
slave->mtd.write = part_write;
|
slave->mtd._write = part_write;
|
||||||
|
|
||||||
if (master->panic_write)
|
if (master->_panic_write)
|
||||||
slave->mtd.panic_write = part_panic_write;
|
slave->mtd._panic_write = part_panic_write;
|
||||||
|
|
||||||
if (master->point && master->unpoint) {
|
if (master->_point && master->_unpoint) {
|
||||||
slave->mtd.point = part_point;
|
slave->mtd._point = part_point;
|
||||||
slave->mtd.unpoint = part_unpoint;
|
slave->mtd._unpoint = part_unpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (master->get_unmapped_area)
|
if (master->_get_unmapped_area)
|
||||||
slave->mtd.get_unmapped_area = part_get_unmapped_area;
|
slave->mtd._get_unmapped_area = part_get_unmapped_area;
|
||||||
if (master->read_oob)
|
if (master->_read_oob)
|
||||||
slave->mtd.read_oob = part_read_oob;
|
slave->mtd._read_oob = part_read_oob;
|
||||||
if (master->write_oob)
|
if (master->_write_oob)
|
||||||
slave->mtd.write_oob = part_write_oob;
|
slave->mtd._write_oob = part_write_oob;
|
||||||
if (master->read_user_prot_reg)
|
if (master->_read_user_prot_reg)
|
||||||
slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
|
slave->mtd._read_user_prot_reg = part_read_user_prot_reg;
|
||||||
if (master->read_fact_prot_reg)
|
if (master->_read_fact_prot_reg)
|
||||||
slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
|
slave->mtd._read_fact_prot_reg = part_read_fact_prot_reg;
|
||||||
if (master->write_user_prot_reg)
|
if (master->_write_user_prot_reg)
|
||||||
slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
|
slave->mtd._write_user_prot_reg = part_write_user_prot_reg;
|
||||||
if (master->lock_user_prot_reg)
|
if (master->_lock_user_prot_reg)
|
||||||
slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
|
slave->mtd._lock_user_prot_reg = part_lock_user_prot_reg;
|
||||||
if (master->get_user_prot_info)
|
if (master->_get_user_prot_info)
|
||||||
slave->mtd.get_user_prot_info = part_get_user_prot_info;
|
slave->mtd._get_user_prot_info = part_get_user_prot_info;
|
||||||
if (master->get_fact_prot_info)
|
if (master->_get_fact_prot_info)
|
||||||
slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
|
slave->mtd._get_fact_prot_info = part_get_fact_prot_info;
|
||||||
if (master->sync)
|
if (master->_sync)
|
||||||
slave->mtd.sync = part_sync;
|
slave->mtd._sync = part_sync;
|
||||||
if (!partno && !master->dev.class && master->suspend && master->resume) {
|
if (!partno && !master->dev.class && master->_suspend &&
|
||||||
slave->mtd.suspend = part_suspend;
|
master->_resume) {
|
||||||
slave->mtd.resume = part_resume;
|
slave->mtd._suspend = part_suspend;
|
||||||
|
slave->mtd._resume = part_resume;
|
||||||
}
|
}
|
||||||
if (master->writev)
|
if (master->_writev)
|
||||||
slave->mtd.writev = part_writev;
|
slave->mtd._writev = part_writev;
|
||||||
if (master->lock)
|
if (master->_lock)
|
||||||
slave->mtd.lock = part_lock;
|
slave->mtd._lock = part_lock;
|
||||||
if (master->unlock)
|
if (master->_unlock)
|
||||||
slave->mtd.unlock = part_unlock;
|
slave->mtd._unlock = part_unlock;
|
||||||
if (master->is_locked)
|
if (master->_is_locked)
|
||||||
slave->mtd.is_locked = part_is_locked;
|
slave->mtd._is_locked = part_is_locked;
|
||||||
if (master->block_isbad)
|
if (master->_block_isbad)
|
||||||
slave->mtd.block_isbad = part_block_isbad;
|
slave->mtd._block_isbad = part_block_isbad;
|
||||||
if (master->block_markbad)
|
if (master->_block_markbad)
|
||||||
slave->mtd.block_markbad = part_block_markbad;
|
slave->mtd._block_markbad = part_block_markbad;
|
||||||
slave->mtd.erase = part_erase;
|
slave->mtd._erase = part_erase;
|
||||||
slave->master = master;
|
slave->master = master;
|
||||||
slave->offset = part->offset;
|
slave->offset = part->offset;
|
||||||
|
|
||||||
@@ -549,7 +516,8 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
|
|||||||
}
|
}
|
||||||
|
|
||||||
slave->mtd.ecclayout = master->ecclayout;
|
slave->mtd.ecclayout = master->ecclayout;
|
||||||
if (master->block_isbad) {
|
slave->mtd.ecc_strength = master->ecc_strength;
|
||||||
|
if (master->_block_isbad) {
|
||||||
uint64_t offs = 0;
|
uint64_t offs = 0;
|
||||||
|
|
||||||
while (offs < slave->mtd.size) {
|
while (offs < slave->mtd.size) {
|
||||||
@@ -761,7 +729,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
|
|||||||
for ( ; ret <= 0 && *types; types++) {
|
for ( ; ret <= 0 && *types; types++) {
|
||||||
parser = get_partition_parser(*types);
|
parser = get_partition_parser(*types);
|
||||||
if (!parser && !request_module("%s", *types))
|
if (!parser && !request_module("%s", *types))
|
||||||
parser = get_partition_parser(*types);
|
parser = get_partition_parser(*types);
|
||||||
if (!parser)
|
if (!parser)
|
||||||
continue;
|
continue;
|
||||||
ret = (*parser->parse_fn)(master, pparts, data);
|
ret = (*parser->parse_fn)(master, pparts, data);
|
||||||
|
|||||||
@@ -314,6 +314,26 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
|
|||||||
load time (assuming you build diskonchip as a module) with the module
|
load time (assuming you build diskonchip as a module) with the module
|
||||||
parameter "inftl_bbt_write=1".
|
parameter "inftl_bbt_write=1".
|
||||||
|
|
||||||
|
config MTD_NAND_DOCG4
|
||||||
|
tristate "Support for DiskOnChip G4 (EXPERIMENTAL)"
|
||||||
|
depends on EXPERIMENTAL
|
||||||
|
select BCH
|
||||||
|
select BITREVERSE
|
||||||
|
help
|
||||||
|
Support for diskonchip G4 nand flash, found in various smartphones and
|
||||||
|
PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
|
||||||
|
Portege G900, Asus P526, and O2 XDA Zinc.
|
||||||
|
|
||||||
|
With this driver you will be able to use UBI and create a ubifs on the
|
||||||
|
device, so you may wish to consider enabling UBI and UBIFS as well.
|
||||||
|
|
||||||
|
These devices ship with the Mys/Sandisk SAFTL formatting, for which
|
||||||
|
there is currently no mtd parser, so you may want to use command line
|
||||||
|
partitioning to segregate write-protected blocks. On the Treo680, the
|
||||||
|
first five erase blocks (256KiB each) are write-protected, followed
|
||||||
|
by the block containing the saftl partition table. This is probably
|
||||||
|
typical.
|
||||||
|
|
||||||
config MTD_NAND_SHARPSL
|
config MTD_NAND_SHARPSL
|
||||||
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
|
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
|
||||||
depends on ARCH_PXA
|
depends on ARCH_PXA
|
||||||
@@ -421,7 +441,6 @@ config MTD_NAND_NANDSIM
|
|||||||
config MTD_NAND_GPMI_NAND
|
config MTD_NAND_GPMI_NAND
|
||||||
bool "GPMI NAND Flash Controller driver"
|
bool "GPMI NAND Flash Controller driver"
|
||||||
depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28)
|
depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28)
|
||||||
select MTD_CMDLINE_PARTS
|
|
||||||
help
|
help
|
||||||
Enables NAND Flash support for IMX23 or IMX28.
|
Enables NAND Flash support for IMX23 or IMX28.
|
||||||
The GPMI controller is very powerful, with the help of BCH
|
The GPMI controller is very powerful, with the help of BCH
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
|
|||||||
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
|
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
|
||||||
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
|
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
|
||||||
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
|
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
|
||||||
|
obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o
|
||||||
obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o
|
obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o
|
||||||
obj-$(CONFIG_MTD_NAND_H1900) += h1910.o
|
obj-$(CONFIG_MTD_NAND_H1900) += h1910.o
|
||||||
obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o
|
obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o
|
||||||
|
|||||||
@@ -585,12 +585,13 @@ static int alauda_init_media(struct alauda *al)
|
|||||||
mtd->writesize = 1<<card->pageshift;
|
mtd->writesize = 1<<card->pageshift;
|
||||||
mtd->type = MTD_NANDFLASH;
|
mtd->type = MTD_NANDFLASH;
|
||||||
mtd->flags = MTD_CAP_NANDFLASH;
|
mtd->flags = MTD_CAP_NANDFLASH;
|
||||||
mtd->read = alauda_read;
|
mtd->_read = alauda_read;
|
||||||
mtd->write = alauda_write;
|
mtd->_write = alauda_write;
|
||||||
mtd->erase = alauda_erase;
|
mtd->_erase = alauda_erase;
|
||||||
mtd->block_isbad = alauda_isbad;
|
mtd->_block_isbad = alauda_isbad;
|
||||||
mtd->priv = al;
|
mtd->priv = al;
|
||||||
mtd->owner = THIS_MODULE;
|
mtd->owner = THIS_MODULE;
|
||||||
|
mtd->ecc_strength = 1;
|
||||||
|
|
||||||
err = mtd_device_register(mtd, NULL, 0);
|
err = mtd_device_register(mtd, NULL, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
@@ -603,6 +603,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
|
|||||||
nand_chip->ecc.hwctl = atmel_nand_hwctl;
|
nand_chip->ecc.hwctl = atmel_nand_hwctl;
|
||||||
nand_chip->ecc.read_page = atmel_nand_read_page;
|
nand_chip->ecc.read_page = atmel_nand_read_page;
|
||||||
nand_chip->ecc.bytes = 4;
|
nand_chip->ecc.bytes = 4;
|
||||||
|
nand_chip->ecc.strength = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nand_chip->chip_delay = 20; /* 20us command delay time */
|
nand_chip->chip_delay = 20; /* 20us command delay time */
|
||||||
|
|||||||
@@ -475,6 +475,14 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)
|
|||||||
largepage_bbt.options = NAND_BBT_SCAN2NDPAGE;
|
largepage_bbt.options = NAND_BBT_SCAN2NDPAGE;
|
||||||
this->badblock_pattern = &largepage_bbt;
|
this->badblock_pattern = &largepage_bbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: ecc strength value of 6 bits per 512 bytes of data is a
|
||||||
|
* conservative guess, given 13 ecc bytes and using bch alg.
|
||||||
|
* (Assume Galois field order m=15 to allow a margin of error.)
|
||||||
|
*/
|
||||||
|
this->ecc.strength = 6;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Now finish off the scan, now that ecc.layout has been initialized. */
|
/* Now finish off the scan, now that ecc.layout has been initialized. */
|
||||||
@@ -487,7 +495,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
/* Register the partitions */
|
/* Register the partitions */
|
||||||
board_mtd->name = "bcm_umi-nand";
|
board_mtd->name = "bcm_umi-nand";
|
||||||
mtd_device_parse_register(board_mtd, NULL, 0, NULL, 0);
|
mtd_device_parse_register(board_mtd, NULL, NULL, NULL, 0);
|
||||||
|
|
||||||
/* Return happy */
|
/* Return happy */
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -702,9 +702,11 @@ static int bf5xx_nand_scan(struct mtd_info *mtd)
|
|||||||
if (likely(mtd->writesize >= 512)) {
|
if (likely(mtd->writesize >= 512)) {
|
||||||
chip->ecc.size = 512;
|
chip->ecc.size = 512;
|
||||||
chip->ecc.bytes = 6;
|
chip->ecc.bytes = 6;
|
||||||
|
chip->ecc.strength = 2;
|
||||||
} else {
|
} else {
|
||||||
chip->ecc.size = 256;
|
chip->ecc.size = 256;
|
||||||
chip->ecc.bytes = 3;
|
chip->ecc.bytes = 3;
|
||||||
|
chip->ecc.strength = 1;
|
||||||
bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET));
|
bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET));
|
||||||
SSYNC();
|
SSYNC();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -783,6 +783,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
|
|||||||
cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
|
cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
|
||||||
cafe->nand.ecc.size = mtd->writesize;
|
cafe->nand.ecc.size = mtd->writesize;
|
||||||
cafe->nand.ecc.bytes = 14;
|
cafe->nand.ecc.bytes = 14;
|
||||||
|
cafe->nand.ecc.strength = 4;
|
||||||
cafe->nand.ecc.hwctl = (void *)cafe_nand_bug;
|
cafe->nand.ecc.hwctl = (void *)cafe_nand_bug;
|
||||||
cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
|
cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
|
||||||
cafe->nand.ecc.correct = (void *)cafe_nand_bug;
|
cafe->nand.ecc.correct = (void *)cafe_nand_bug;
|
||||||
@@ -799,7 +800,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
|
|||||||
pci_set_drvdata(pdev, mtd);
|
pci_set_drvdata(pdev, mtd);
|
||||||
|
|
||||||
mtd->name = "cafe_nand";
|
mtd->name = "cafe_nand";
|
||||||
mtd_device_parse_register(mtd, part_probes, 0, NULL, 0);
|
mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ static int __init cmx270_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Register the partitions */
|
/* Register the partitions */
|
||||||
ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, 0,
|
ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, NULL,
|
||||||
partition_info, NUM_PARTITIONS);
|
partition_info, NUM_PARTITIONS);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_scan;
|
goto err_scan;
|
||||||
|
|||||||
@@ -248,6 +248,8 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
|
|||||||
goto out_ior;
|
goto out_ior;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->ecc.strength = 1;
|
||||||
|
|
||||||
new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
|
new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
|
||||||
|
|
||||||
cs553x_mtd[cs] = new_mtd;
|
cs553x_mtd[cs] = new_mtd;
|
||||||
@@ -313,7 +315,7 @@ static int __init cs553x_init(void)
|
|||||||
for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
|
for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
|
||||||
if (cs553x_mtd[i]) {
|
if (cs553x_mtd[i]) {
|
||||||
/* If any devices registered, return success. Else the last error. */
|
/* If any devices registered, return success. Else the last error. */
|
||||||
mtd_device_parse_register(cs553x_mtd[i], NULL, 0,
|
mtd_device_parse_register(cs553x_mtd[i], NULL, NULL,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -641,6 +641,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
|
|||||||
info->chip.ecc.bytes = 3;
|
info->chip.ecc.bytes = 3;
|
||||||
}
|
}
|
||||||
info->chip.ecc.size = 512;
|
info->chip.ecc.size = 512;
|
||||||
|
info->chip.ecc.strength = pdata->ecc_bits;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
@@ -752,8 +753,8 @@ syndrome_done:
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_scan;
|
goto err_scan;
|
||||||
|
|
||||||
ret = mtd_device_parse_register(&info->mtd, NULL, 0,
|
ret = mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts,
|
||||||
pdata->parts, pdata->nr_parts);
|
pdata->nr_parts);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_scan;
|
goto err_scan;
|
||||||
|
|||||||
@@ -1590,6 +1590,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||||||
ECC_15BITS * (denali->mtd.writesize /
|
ECC_15BITS * (denali->mtd.writesize /
|
||||||
ECC_SECTOR_SIZE)))) {
|
ECC_SECTOR_SIZE)))) {
|
||||||
/* if MLC OOB size is large enough, use 15bit ECC*/
|
/* if MLC OOB size is large enough, use 15bit ECC*/
|
||||||
|
denali->nand.ecc.strength = 15;
|
||||||
denali->nand.ecc.layout = &nand_15bit_oob;
|
denali->nand.ecc.layout = &nand_15bit_oob;
|
||||||
denali->nand.ecc.bytes = ECC_15BITS;
|
denali->nand.ecc.bytes = ECC_15BITS;
|
||||||
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
|
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
|
||||||
@@ -1600,12 +1601,14 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||||||
" contain 8bit ECC correction codes");
|
" contain 8bit ECC correction codes");
|
||||||
goto failed_req_irq;
|
goto failed_req_irq;
|
||||||
} else {
|
} else {
|
||||||
|
denali->nand.ecc.strength = 8;
|
||||||
denali->nand.ecc.layout = &nand_8bit_oob;
|
denali->nand.ecc.layout = &nand_8bit_oob;
|
||||||
denali->nand.ecc.bytes = ECC_8BITS;
|
denali->nand.ecc.bytes = ECC_8BITS;
|
||||||
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
|
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
denali->nand.ecc.bytes *= denali->devnum;
|
denali->nand.ecc.bytes *= denali->devnum;
|
||||||
|
denali->nand.ecc.strength *= denali->devnum;
|
||||||
denali->nand.ecc.layout->eccbytes *=
|
denali->nand.ecc.layout->eccbytes *=
|
||||||
denali->mtd.writesize / ECC_SECTOR_SIZE;
|
denali->mtd.writesize / ECC_SECTOR_SIZE;
|
||||||
denali->nand.ecc.layout->oobfree[0].offset =
|
denali->nand.ecc.layout->oobfree[0].offset =
|
||||||
|
|||||||
@@ -1653,6 +1653,7 @@ static int __init doc_probe(unsigned long physadr)
|
|||||||
nand->ecc.mode = NAND_ECC_HW_SYNDROME;
|
nand->ecc.mode = NAND_ECC_HW_SYNDROME;
|
||||||
nand->ecc.size = 512;
|
nand->ecc.size = 512;
|
||||||
nand->ecc.bytes = 6;
|
nand->ecc.bytes = 6;
|
||||||
|
nand->ecc.strength = 2;
|
||||||
nand->bbt_options = NAND_BBT_USE_FLASH;
|
nand->bbt_options = NAND_BBT_USE_FLASH;
|
||||||
|
|
||||||
doc->physadr = physadr;
|
doc->physadr = physadr;
|
||||||
|
|||||||
1377
drivers/mtd/nand/docg4.c
Normal file
1377
drivers/mtd/nand/docg4.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -813,6 +813,12 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
|
|||||||
&fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0;
|
&fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0;
|
||||||
chip->ecc.size = 512;
|
chip->ecc.size = 512;
|
||||||
chip->ecc.bytes = 3;
|
chip->ecc.bytes = 3;
|
||||||
|
chip->ecc.strength = 1;
|
||||||
|
/*
|
||||||
|
* FIXME: can hardware ecc correct 4 bitflips if page size is
|
||||||
|
* 2k? Then does hardware report number of corrections for this
|
||||||
|
* case? If so, ecc_stats reporting needs to be fixed as well.
|
||||||
|
*/
|
||||||
} else {
|
} else {
|
||||||
/* otherwise fall back to default software ECC */
|
/* otherwise fall back to default software ECC */
|
||||||
chip->ecc.mode = NAND_ECC_SOFT;
|
chip->ecc.mode = NAND_ECC_SOFT;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -848,7 +848,10 @@ int gpmi_send_command(struct gpmi_nand_data *this)
|
|||||||
|
|
||||||
sg_init_one(sgl, this->cmd_buffer, this->command_length);
|
sg_init_one(sgl, this->cmd_buffer, this->command_length);
|
||||||
dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
|
dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
|
||||||
desc = dmaengine_prep_slave_sg(channel, sgl, 1, DMA_MEM_TO_DEV, 1);
|
desc = dmaengine_prep_slave_sg(channel,
|
||||||
|
sgl, 1, DMA_MEM_TO_DEV,
|
||||||
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
|
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
pr_err("step 2 error\n");
|
pr_err("step 2 error\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -889,7 +892,8 @@ int gpmi_send_data(struct gpmi_nand_data *this)
|
|||||||
/* [2] send DMA request */
|
/* [2] send DMA request */
|
||||||
prepare_data_dma(this, DMA_TO_DEVICE);
|
prepare_data_dma(this, DMA_TO_DEVICE);
|
||||||
desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
|
desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
|
||||||
1, DMA_MEM_TO_DEV, 1);
|
1, DMA_MEM_TO_DEV,
|
||||||
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
pr_err("step 2 error\n");
|
pr_err("step 2 error\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -925,7 +929,8 @@ int gpmi_read_data(struct gpmi_nand_data *this)
|
|||||||
/* [2] : send DMA request */
|
/* [2] : send DMA request */
|
||||||
prepare_data_dma(this, DMA_FROM_DEVICE);
|
prepare_data_dma(this, DMA_FROM_DEVICE);
|
||||||
desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
|
desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
|
||||||
1, DMA_DEV_TO_MEM, 1);
|
1, DMA_DEV_TO_MEM,
|
||||||
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
pr_err("step 2 error\n");
|
pr_err("step 2 error\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -970,8 +975,10 @@ int gpmi_send_page(struct gpmi_nand_data *this,
|
|||||||
pio[4] = payload;
|
pio[4] = payload;
|
||||||
pio[5] = auxiliary;
|
pio[5] = auxiliary;
|
||||||
|
|
||||||
desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
|
desc = dmaengine_prep_slave_sg(channel,
|
||||||
ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
|
(struct scatterlist *)pio,
|
||||||
|
ARRAY_SIZE(pio), DMA_TRANS_NONE,
|
||||||
|
DMA_CTRL_ACK);
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
pr_err("step 2 error\n");
|
pr_err("step 2 error\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1035,7 +1042,8 @@ int gpmi_read_page(struct gpmi_nand_data *this,
|
|||||||
pio[5] = auxiliary;
|
pio[5] = auxiliary;
|
||||||
desc = dmaengine_prep_slave_sg(channel,
|
desc = dmaengine_prep_slave_sg(channel,
|
||||||
(struct scatterlist *)pio,
|
(struct scatterlist *)pio,
|
||||||
ARRAY_SIZE(pio), DMA_TRANS_NONE, 1);
|
ARRAY_SIZE(pio), DMA_TRANS_NONE,
|
||||||
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
pr_err("step 2 error\n");
|
pr_err("step 2 error\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1052,9 +1060,11 @@ int gpmi_read_page(struct gpmi_nand_data *this,
|
|||||||
| BF_GPMI_CTRL0_ADDRESS(address)
|
| BF_GPMI_CTRL0_ADDRESS(address)
|
||||||
| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
|
| BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
|
||||||
pio[1] = 0;
|
pio[1] = 0;
|
||||||
|
pio[2] = 0; /* clear GPMI_HW_GPMI_ECCCTRL, disable the BCH. */
|
||||||
desc = dmaengine_prep_slave_sg(channel,
|
desc = dmaengine_prep_slave_sg(channel,
|
||||||
(struct scatterlist *)pio, 2,
|
(struct scatterlist *)pio, 3,
|
||||||
DMA_TRANS_NONE, 1);
|
DMA_TRANS_NONE,
|
||||||
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
pr_err("step 3 error\n");
|
pr_err("step 3 error\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -1124,7 +1124,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||||||
chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
|
chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
|
||||||
|
|
||||||
/* Do we have a flash based bad block table ? */
|
/* Do we have a flash based bad block table ? */
|
||||||
if (chip->options & NAND_BBT_USE_FLASH)
|
if (chip->bbt_options & NAND_BBT_USE_FLASH)
|
||||||
ret = nand_update_bbt(mtd, ofs);
|
ret = nand_update_bbt(mtd, ofs);
|
||||||
else {
|
else {
|
||||||
chipnr = (int)(ofs >> chip->chip_shift);
|
chipnr = (int)(ofs >> chip->chip_shift);
|
||||||
@@ -1155,7 +1155,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devinit nand_boot_set_geometry(struct gpmi_nand_data *this)
|
static int nand_boot_set_geometry(struct gpmi_nand_data *this)
|
||||||
{
|
{
|
||||||
struct boot_rom_geometry *geometry = &this->rom_geometry;
|
struct boot_rom_geometry *geometry = &this->rom_geometry;
|
||||||
|
|
||||||
@@ -1182,7 +1182,7 @@ static int __devinit nand_boot_set_geometry(struct gpmi_nand_data *this)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *fingerprint = "STMP";
|
static const char *fingerprint = "STMP";
|
||||||
static int __devinit mx23_check_transcription_stamp(struct gpmi_nand_data *this)
|
static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
|
||||||
{
|
{
|
||||||
struct boot_rom_geometry *rom_geo = &this->rom_geometry;
|
struct boot_rom_geometry *rom_geo = &this->rom_geometry;
|
||||||
struct device *dev = this->dev;
|
struct device *dev = this->dev;
|
||||||
@@ -1239,7 +1239,7 @@ static int __devinit mx23_check_transcription_stamp(struct gpmi_nand_data *this)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Writes a transcription stamp. */
|
/* Writes a transcription stamp. */
|
||||||
static int __devinit mx23_write_transcription_stamp(struct gpmi_nand_data *this)
|
static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
|
||||||
{
|
{
|
||||||
struct device *dev = this->dev;
|
struct device *dev = this->dev;
|
||||||
struct boot_rom_geometry *rom_geo = &this->rom_geometry;
|
struct boot_rom_geometry *rom_geo = &this->rom_geometry;
|
||||||
@@ -1322,7 +1322,7 @@ static int __devinit mx23_write_transcription_stamp(struct gpmi_nand_data *this)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devinit mx23_boot_init(struct gpmi_nand_data *this)
|
static int mx23_boot_init(struct gpmi_nand_data *this)
|
||||||
{
|
{
|
||||||
struct device *dev = this->dev;
|
struct device *dev = this->dev;
|
||||||
struct nand_chip *chip = &this->nand;
|
struct nand_chip *chip = &this->nand;
|
||||||
@@ -1391,7 +1391,7 @@ static int __devinit mx23_boot_init(struct gpmi_nand_data *this)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devinit nand_boot_init(struct gpmi_nand_data *this)
|
static int nand_boot_init(struct gpmi_nand_data *this)
|
||||||
{
|
{
|
||||||
nand_boot_set_geometry(this);
|
nand_boot_set_geometry(this);
|
||||||
|
|
||||||
@@ -1401,7 +1401,7 @@ static int __devinit nand_boot_init(struct gpmi_nand_data *this)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devinit gpmi_set_geometry(struct gpmi_nand_data *this)
|
static int gpmi_set_geometry(struct gpmi_nand_data *this)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#include <linux/mtd/nand.h>
|
#include <linux/mtd/nand.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <mach/dma.h>
|
#include <linux/fsl/mxs-dma.h>
|
||||||
|
|
||||||
struct resources {
|
struct resources {
|
||||||
void *gpmi_regs;
|
void *gpmi_regs;
|
||||||
|
|||||||
@@ -135,8 +135,8 @@ static int __init h1910_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Register the partitions */
|
/* Register the partitions */
|
||||||
mtd_device_parse_register(h1910_nand_mtd, NULL, 0,
|
mtd_device_parse_register(h1910_nand_mtd, NULL, NULL, partition_info,
|
||||||
partition_info, NUM_PARTITIONS);
|
NUM_PARTITIONS);
|
||||||
|
|
||||||
/* Return happy */
|
/* Return happy */
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -332,6 +332,11 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
|
|||||||
chip->ecc.mode = NAND_ECC_HW_OOB_FIRST;
|
chip->ecc.mode = NAND_ECC_HW_OOB_FIRST;
|
||||||
chip->ecc.size = 512;
|
chip->ecc.size = 512;
|
||||||
chip->ecc.bytes = 9;
|
chip->ecc.bytes = 9;
|
||||||
|
chip->ecc.strength = 2;
|
||||||
|
/*
|
||||||
|
* FIXME: ecc_strength value of 2 bits per 512 bytes of data is a
|
||||||
|
* conservative guess, given 9 ecc bytes and reed-solomon alg.
|
||||||
|
*/
|
||||||
|
|
||||||
if (pdata)
|
if (pdata)
|
||||||
chip->ecc.layout = pdata->ecc_layout;
|
chip->ecc.layout = pdata->ecc_layout;
|
||||||
@@ -367,9 +372,9 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
|
|||||||
goto err_gpio_free;
|
goto err_gpio_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mtd_device_parse_register(mtd, NULL, 0,
|
ret = mtd_device_parse_register(mtd, NULL, NULL,
|
||||||
pdata ? pdata->partitions : NULL,
|
pdata ? pdata->partitions : NULL,
|
||||||
pdata ? pdata->num_partitions : 0);
|
pdata ? pdata->num_partitions : 0);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "Failed to add mtd device\n");
|
dev_err(&pdev->dev, "Failed to add mtd device\n");
|
||||||
|
|||||||
@@ -1225,9 +1225,16 @@ static int __init mxcnd_probe(struct platform_device *pdev)
|
|||||||
goto escan;
|
goto escan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->ecc.mode == NAND_ECC_HW) {
|
||||||
|
if (nfc_is_v1())
|
||||||
|
this->ecc.strength = 1;
|
||||||
|
else
|
||||||
|
this->ecc.strength = (host->eccsize == 4) ? 4 : 8;
|
||||||
|
}
|
||||||
|
|
||||||
/* Register the partitions */
|
/* Register the partitions */
|
||||||
mtd_device_parse_register(mtd, part_probes, 0,
|
mtd_device_parse_register(mtd, part_probes, NULL, pdata->parts,
|
||||||
pdata->parts, pdata->nr_parts);
|
pdata->nr_parts);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, host);
|
platform_set_drvdata(pdev, host);
|
||||||
|
|
||||||
|
|||||||
@@ -123,12 +123,6 @@ static int check_offs_len(struct mtd_info *mtd,
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do not allow past end of device */
|
|
||||||
if (ofs + len > mtd->size) {
|
|
||||||
pr_debug("%s: past end of device\n", __func__);
|
|
||||||
ret = -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,7 +332,7 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
|
|||||||
*/
|
*/
|
||||||
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
||||||
{
|
{
|
||||||
int page, chipnr, res = 0;
|
int page, chipnr, res = 0, i = 0;
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
u16 bad;
|
u16 bad;
|
||||||
|
|
||||||
@@ -356,23 +350,29 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
|||||||
chip->select_chip(mtd, chipnr);
|
chip->select_chip(mtd, chipnr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chip->options & NAND_BUSWIDTH_16) {
|
do {
|
||||||
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
|
if (chip->options & NAND_BUSWIDTH_16) {
|
||||||
page);
|
chip->cmdfunc(mtd, NAND_CMD_READOOB,
|
||||||
bad = cpu_to_le16(chip->read_word(mtd));
|
chip->badblockpos & 0xFE, page);
|
||||||
if (chip->badblockpos & 0x1)
|
bad = cpu_to_le16(chip->read_word(mtd));
|
||||||
bad >>= 8;
|
if (chip->badblockpos & 0x1)
|
||||||
else
|
bad >>= 8;
|
||||||
bad &= 0xFF;
|
else
|
||||||
} else {
|
bad &= 0xFF;
|
||||||
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
|
} else {
|
||||||
bad = chip->read_byte(mtd);
|
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
|
||||||
}
|
page);
|
||||||
|
bad = chip->read_byte(mtd);
|
||||||
|
}
|
||||||
|
|
||||||
if (likely(chip->badblockbits == 8))
|
if (likely(chip->badblockbits == 8))
|
||||||
res = bad != 0xFF;
|
res = bad != 0xFF;
|
||||||
else
|
else
|
||||||
res = hweight8(bad) < chip->badblockbits;
|
res = hweight8(bad) < chip->badblockbits;
|
||||||
|
ofs += mtd->writesize;
|
||||||
|
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
|
||||||
|
i++;
|
||||||
|
} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
|
||||||
|
|
||||||
if (getchip)
|
if (getchip)
|
||||||
nand_release_device(mtd);
|
nand_release_device(mtd);
|
||||||
@@ -386,51 +386,79 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
|||||||
* @ofs: offset from device start
|
* @ofs: offset from device start
|
||||||
*
|
*
|
||||||
* This is the default implementation, which can be overridden by a hardware
|
* This is the default implementation, which can be overridden by a hardware
|
||||||
* specific driver.
|
* specific driver. We try operations in the following order, according to our
|
||||||
|
* bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH):
|
||||||
|
* (1) erase the affected block, to allow OOB marker to be written cleanly
|
||||||
|
* (2) update in-memory BBT
|
||||||
|
* (3) write bad block marker to OOB area of affected block
|
||||||
|
* (4) update flash-based BBT
|
||||||
|
* Note that we retain the first error encountered in (3) or (4), finish the
|
||||||
|
* procedures, and dump the error in the end.
|
||||||
*/
|
*/
|
||||||
static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
uint8_t buf[2] = { 0, 0 };
|
uint8_t buf[2] = { 0, 0 };
|
||||||
int block, ret, i = 0;
|
int block, res, ret = 0, i = 0;
|
||||||
|
int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM);
|
||||||
|
|
||||||
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
|
if (write_oob) {
|
||||||
ofs += mtd->erasesize - mtd->writesize;
|
struct erase_info einfo;
|
||||||
|
|
||||||
|
/* Attempt erase before marking OOB */
|
||||||
|
memset(&einfo, 0, sizeof(einfo));
|
||||||
|
einfo.mtd = mtd;
|
||||||
|
einfo.addr = ofs;
|
||||||
|
einfo.len = 1 << chip->phys_erase_shift;
|
||||||
|
nand_erase_nand(mtd, &einfo, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get block number */
|
/* Get block number */
|
||||||
block = (int)(ofs >> chip->bbt_erase_shift);
|
block = (int)(ofs >> chip->bbt_erase_shift);
|
||||||
|
/* Mark block bad in memory-based BBT */
|
||||||
if (chip->bbt)
|
if (chip->bbt)
|
||||||
chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
|
chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
|
||||||
|
|
||||||
/* Do we have a flash based bad block table? */
|
/* Write bad block marker to OOB */
|
||||||
if (chip->bbt_options & NAND_BBT_USE_FLASH)
|
if (write_oob) {
|
||||||
ret = nand_update_bbt(mtd, ofs);
|
|
||||||
else {
|
|
||||||
struct mtd_oob_ops ops;
|
struct mtd_oob_ops ops;
|
||||||
|
loff_t wr_ofs = ofs;
|
||||||
|
|
||||||
nand_get_device(chip, mtd, FL_WRITING);
|
nand_get_device(chip, mtd, FL_WRITING);
|
||||||
|
|
||||||
/*
|
|
||||||
* Write to first two pages if necessary. If we write to more
|
|
||||||
* than one location, the first error encountered quits the
|
|
||||||
* procedure. We write two bytes per location, so we dont have
|
|
||||||
* to mess with 16 bit access.
|
|
||||||
*/
|
|
||||||
ops.len = ops.ooblen = 2;
|
|
||||||
ops.datbuf = NULL;
|
ops.datbuf = NULL;
|
||||||
ops.oobbuf = buf;
|
ops.oobbuf = buf;
|
||||||
ops.ooboffs = chip->badblockpos & ~0x01;
|
ops.ooboffs = chip->badblockpos;
|
||||||
|
if (chip->options & NAND_BUSWIDTH_16) {
|
||||||
|
ops.ooboffs &= ~0x01;
|
||||||
|
ops.len = ops.ooblen = 2;
|
||||||
|
} else {
|
||||||
|
ops.len = ops.ooblen = 1;
|
||||||
|
}
|
||||||
ops.mode = MTD_OPS_PLACE_OOB;
|
ops.mode = MTD_OPS_PLACE_OOB;
|
||||||
|
|
||||||
|
/* Write to first/last page(s) if necessary */
|
||||||
|
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
|
||||||
|
wr_ofs += mtd->erasesize - mtd->writesize;
|
||||||
do {
|
do {
|
||||||
ret = nand_do_write_oob(mtd, ofs, &ops);
|
res = nand_do_write_oob(mtd, wr_ofs, &ops);
|
||||||
|
if (!ret)
|
||||||
|
ret = res;
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
ofs += mtd->writesize;
|
wr_ofs += mtd->writesize;
|
||||||
} while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) &&
|
} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
|
||||||
i < 2);
|
|
||||||
|
|
||||||
nand_release_device(mtd);
|
nand_release_device(mtd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update flash-based bad block table */
|
||||||
|
if (chip->bbt_options & NAND_BBT_USE_FLASH) {
|
||||||
|
res = nand_update_bbt(mtd, ofs);
|
||||||
|
if (!ret)
|
||||||
|
ret = res;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
mtd->ecc_stats.badblocks++;
|
mtd->ecc_stats.badblocks++;
|
||||||
|
|
||||||
@@ -1586,25 +1614,14 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||||||
struct mtd_oob_ops ops;
|
struct mtd_oob_ops ops;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Do not allow reads past end of device */
|
|
||||||
if ((from + len) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
nand_get_device(chip, mtd, FL_READING);
|
nand_get_device(chip, mtd, FL_READING);
|
||||||
|
|
||||||
ops.len = len;
|
ops.len = len;
|
||||||
ops.datbuf = buf;
|
ops.datbuf = buf;
|
||||||
ops.oobbuf = NULL;
|
ops.oobbuf = NULL;
|
||||||
ops.mode = 0;
|
ops.mode = 0;
|
||||||
|
|
||||||
ret = nand_do_read_ops(mtd, from, &ops);
|
ret = nand_do_read_ops(mtd, from, &ops);
|
||||||
|
|
||||||
*retlen = ops.retlen;
|
*retlen = ops.retlen;
|
||||||
|
|
||||||
nand_release_device(mtd);
|
nand_release_device(mtd);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2293,12 +2310,6 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
struct mtd_oob_ops ops;
|
struct mtd_oob_ops ops;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Do not allow reads past end of device */
|
|
||||||
if ((to + len) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Wait for the device to get ready */
|
/* Wait for the device to get ready */
|
||||||
panic_nand_wait(mtd, chip, 400);
|
panic_nand_wait(mtd, chip, 400);
|
||||||
|
|
||||||
@@ -2333,25 +2344,14 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||||||
struct mtd_oob_ops ops;
|
struct mtd_oob_ops ops;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Do not allow reads past end of device */
|
|
||||||
if ((to + len) > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
nand_get_device(chip, mtd, FL_WRITING);
|
nand_get_device(chip, mtd, FL_WRITING);
|
||||||
|
|
||||||
ops.len = len;
|
ops.len = len;
|
||||||
ops.datbuf = (uint8_t *)buf;
|
ops.datbuf = (uint8_t *)buf;
|
||||||
ops.oobbuf = NULL;
|
ops.oobbuf = NULL;
|
||||||
ops.mode = 0;
|
ops.mode = 0;
|
||||||
|
|
||||||
ret = nand_do_write_ops(mtd, to, &ops);
|
ret = nand_do_write_ops(mtd, to, &ops);
|
||||||
|
|
||||||
*retlen = ops.retlen;
|
*retlen = ops.retlen;
|
||||||
|
|
||||||
nand_release_device(mtd);
|
nand_release_device(mtd);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2550,8 +2550,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
|
|||||||
if (check_offs_len(mtd, instr->addr, instr->len))
|
if (check_offs_len(mtd, instr->addr, instr->len))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
|
|
||||||
|
|
||||||
/* Grab the lock and see if the device is available */
|
/* Grab the lock and see if the device is available */
|
||||||
nand_get_device(chip, mtd, FL_ERASING);
|
nand_get_device(chip, mtd, FL_ERASING);
|
||||||
|
|
||||||
@@ -2715,10 +2713,6 @@ static void nand_sync(struct mtd_info *mtd)
|
|||||||
*/
|
*/
|
||||||
static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
|
static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
|
||||||
{
|
{
|
||||||
/* Check for invalid offset */
|
|
||||||
if (offs > mtd->size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return nand_block_checkbad(mtd, offs, 1, 0);
|
return nand_block_checkbad(mtd, offs, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2857,7 +2851,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
|||||||
chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
|
chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pr_info("ONFI flash detected\n");
|
|
||||||
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
|
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
|
chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
|
||||||
@@ -2898,7 +2891,8 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
|||||||
mtd->writesize = le32_to_cpu(p->byte_per_page);
|
mtd->writesize = le32_to_cpu(p->byte_per_page);
|
||||||
mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
|
mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
|
||||||
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
||||||
chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize;
|
chip->chipsize = le32_to_cpu(p->blocks_per_lun);
|
||||||
|
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
|
||||||
*busw = 0;
|
*busw = 0;
|
||||||
if (le16_to_cpu(p->features) & 1)
|
if (le16_to_cpu(p->features) & 1)
|
||||||
*busw = NAND_BUSWIDTH_16;
|
*busw = NAND_BUSWIDTH_16;
|
||||||
@@ -2907,6 +2901,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
|||||||
chip->options |= (NAND_NO_READRDY |
|
chip->options |= (NAND_NO_READRDY |
|
||||||
NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK;
|
NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK;
|
||||||
|
|
||||||
|
pr_info("ONFI flash detected\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3238,6 +3233,10 @@ int nand_scan_tail(struct mtd_info *mtd)
|
|||||||
int i;
|
int i;
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
|
|
||||||
|
/* New bad blocks should be marked in OOB, flash-based BBT, or both */
|
||||||
|
BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
|
||||||
|
!(chip->bbt_options & NAND_BBT_USE_FLASH));
|
||||||
|
|
||||||
if (!(chip->options & NAND_OWN_BUFFERS))
|
if (!(chip->options & NAND_OWN_BUFFERS))
|
||||||
chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
|
chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
|
||||||
if (!chip->buffers)
|
if (!chip->buffers)
|
||||||
@@ -3350,6 +3349,7 @@ int nand_scan_tail(struct mtd_info *mtd)
|
|||||||
if (!chip->ecc.size)
|
if (!chip->ecc.size)
|
||||||
chip->ecc.size = 256;
|
chip->ecc.size = 256;
|
||||||
chip->ecc.bytes = 3;
|
chip->ecc.bytes = 3;
|
||||||
|
chip->ecc.strength = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_ECC_SOFT_BCH:
|
case NAND_ECC_SOFT_BCH:
|
||||||
@@ -3384,6 +3384,8 @@ int nand_scan_tail(struct mtd_info *mtd)
|
|||||||
pr_warn("BCH ECC initialization failed!\n");
|
pr_warn("BCH ECC initialization failed!\n");
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
chip->ecc.strength =
|
||||||
|
chip->ecc.bytes*8 / fls(8*chip->ecc.size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_ECC_NONE:
|
case NAND_ECC_NONE:
|
||||||
@@ -3397,6 +3399,7 @@ int nand_scan_tail(struct mtd_info *mtd)
|
|||||||
chip->ecc.write_oob = nand_write_oob_std;
|
chip->ecc.write_oob = nand_write_oob_std;
|
||||||
chip->ecc.size = mtd->writesize;
|
chip->ecc.size = mtd->writesize;
|
||||||
chip->ecc.bytes = 0;
|
chip->ecc.bytes = 0;
|
||||||
|
chip->ecc.strength = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -3461,25 +3464,26 @@ int nand_scan_tail(struct mtd_info *mtd)
|
|||||||
mtd->type = MTD_NANDFLASH;
|
mtd->type = MTD_NANDFLASH;
|
||||||
mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
|
mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
|
||||||
MTD_CAP_NANDFLASH;
|
MTD_CAP_NANDFLASH;
|
||||||
mtd->erase = nand_erase;
|
mtd->_erase = nand_erase;
|
||||||
mtd->point = NULL;
|
mtd->_point = NULL;
|
||||||
mtd->unpoint = NULL;
|
mtd->_unpoint = NULL;
|
||||||
mtd->read = nand_read;
|
mtd->_read = nand_read;
|
||||||
mtd->write = nand_write;
|
mtd->_write = nand_write;
|
||||||
mtd->panic_write = panic_nand_write;
|
mtd->_panic_write = panic_nand_write;
|
||||||
mtd->read_oob = nand_read_oob;
|
mtd->_read_oob = nand_read_oob;
|
||||||
mtd->write_oob = nand_write_oob;
|
mtd->_write_oob = nand_write_oob;
|
||||||
mtd->sync = nand_sync;
|
mtd->_sync = nand_sync;
|
||||||
mtd->lock = NULL;
|
mtd->_lock = NULL;
|
||||||
mtd->unlock = NULL;
|
mtd->_unlock = NULL;
|
||||||
mtd->suspend = nand_suspend;
|
mtd->_suspend = nand_suspend;
|
||||||
mtd->resume = nand_resume;
|
mtd->_resume = nand_resume;
|
||||||
mtd->block_isbad = nand_block_isbad;
|
mtd->_block_isbad = nand_block_isbad;
|
||||||
mtd->block_markbad = nand_block_markbad;
|
mtd->_block_markbad = nand_block_markbad;
|
||||||
mtd->writebufsize = mtd->writesize;
|
mtd->writebufsize = mtd->writesize;
|
||||||
|
|
||||||
/* propagate ecc.layout to mtd_info */
|
/* propagate ecc info to mtd_info */
|
||||||
mtd->ecclayout = chip->ecc.layout;
|
mtd->ecclayout = chip->ecc.layout;
|
||||||
|
mtd->ecc_strength = chip->ecc.strength * chip->ecc.steps;
|
||||||
|
|
||||||
/* Check, if we should skip the bad block table scan */
|
/* Check, if we should skip the bad block table scan */
|
||||||
if (chip->options & NAND_SKIP_BBTSCAN)
|
if (chip->options & NAND_SKIP_BBTSCAN)
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
|
|||||||
chip->ecc.mode = NAND_ECC_HW;
|
chip->ecc.mode = NAND_ECC_HW;
|
||||||
chip->ecc.size = 256;
|
chip->ecc.size = 256;
|
||||||
chip->ecc.bytes = 3;
|
chip->ecc.bytes = 3;
|
||||||
|
chip->ecc.strength = 1;
|
||||||
chip->priv = ndfc;
|
chip->priv = ndfc;
|
||||||
|
|
||||||
ndfc->mtd.priv = chip;
|
ndfc->mtd.priv = chip;
|
||||||
|
|||||||
@@ -1058,6 +1058,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
|
|||||||
(pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)) {
|
(pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)) {
|
||||||
info->nand.ecc.bytes = 3;
|
info->nand.ecc.bytes = 3;
|
||||||
info->nand.ecc.size = 512;
|
info->nand.ecc.size = 512;
|
||||||
|
info->nand.ecc.strength = 1;
|
||||||
info->nand.ecc.calculate = omap_calculate_ecc;
|
info->nand.ecc.calculate = omap_calculate_ecc;
|
||||||
info->nand.ecc.hwctl = omap_enable_hwecc;
|
info->nand.ecc.hwctl = omap_enable_hwecc;
|
||||||
info->nand.ecc.correct = omap_correct_data;
|
info->nand.ecc.correct = omap_correct_data;
|
||||||
@@ -1101,8 +1102,8 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
|
|||||||
goto out_release_mem_region;
|
goto out_release_mem_region;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtd_device_parse_register(&info->mtd, NULL, 0,
|
mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts,
|
||||||
pdata->parts, pdata->nr_parts);
|
pdata->nr_parts);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, &info->mtd);
|
platform_set_drvdata(pdev, &info->mtd);
|
||||||
|
|
||||||
|
|||||||
@@ -129,8 +129,8 @@ static int __init orion_nand_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mtd->name = "orion_nand";
|
mtd->name = "orion_nand";
|
||||||
ret = mtd_device_parse_register(mtd, NULL, 0,
|
ret = mtd_device_parse_register(mtd, NULL, NULL, board->parts,
|
||||||
board->parts, board->nr_parts);
|
board->nr_parts);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
nand_release(mtd);
|
nand_release(mtd);
|
||||||
goto no_dev;
|
goto no_dev;
|
||||||
|
|||||||
@@ -99,8 +99,9 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = mtd_device_parse_register(&data->mtd,
|
err = mtd_device_parse_register(&data->mtd,
|
||||||
pdata->chip.part_probe_types, 0,
|
pdata->chip.part_probe_types, NULL,
|
||||||
pdata->chip.partitions, pdata->chip.nr_partitions);
|
pdata->chip.partitions,
|
||||||
|
pdata->chip.nr_partitions);
|
||||||
|
|
||||||
if (!err)
|
if (!err)
|
||||||
return err;
|
return err;
|
||||||
|
|||||||
@@ -275,11 +275,10 @@ static int __init ppchameleonevb_init(void)
|
|||||||
ppchameleon_mtd->name = "ppchameleon-nand";
|
ppchameleon_mtd->name = "ppchameleon-nand";
|
||||||
|
|
||||||
/* Register the partitions */
|
/* Register the partitions */
|
||||||
mtd_device_parse_register(ppchameleon_mtd, NULL, 0,
|
mtd_device_parse_register(ppchameleon_mtd, NULL, NULL,
|
||||||
ppchameleon_mtd->size == NAND_SMALL_SIZE ?
|
ppchameleon_mtd->size == NAND_SMALL_SIZE ?
|
||||||
partition_info_me :
|
partition_info_me : partition_info_hi,
|
||||||
partition_info_hi,
|
NUM_PARTITIONS);
|
||||||
NUM_PARTITIONS);
|
|
||||||
|
|
||||||
nand_evb_init:
|
nand_evb_init:
|
||||||
/****************************
|
/****************************
|
||||||
@@ -365,11 +364,10 @@ static int __init ppchameleonevb_init(void)
|
|||||||
ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME;
|
ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME;
|
||||||
|
|
||||||
/* Register the partitions */
|
/* Register the partitions */
|
||||||
mtd_device_parse_register(ppchameleonevb_mtd, NULL, 0,
|
mtd_device_parse_register(ppchameleonevb_mtd, NULL, NULL,
|
||||||
ppchameleon_mtd->size == NAND_SMALL_SIZE ?
|
ppchameleon_mtd->size == NAND_SMALL_SIZE ?
|
||||||
partition_info_me :
|
partition_info_me : partition_info_hi,
|
||||||
partition_info_hi,
|
NUM_PARTITIONS);
|
||||||
NUM_PARTITIONS);
|
|
||||||
|
|
||||||
/* Return happy */
|
/* Return happy */
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1002,6 +1002,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
|
|||||||
KEEP_CONFIG:
|
KEEP_CONFIG:
|
||||||
chip->ecc.mode = NAND_ECC_HW;
|
chip->ecc.mode = NAND_ECC_HW;
|
||||||
chip->ecc.size = host->page_size;
|
chip->ecc.size = host->page_size;
|
||||||
|
chip->ecc.strength = 1;
|
||||||
|
|
||||||
chip->options = NAND_NO_AUTOINCR;
|
chip->options = NAND_NO_AUTOINCR;
|
||||||
chip->options |= NAND_NO_READRDY;
|
chip->options |= NAND_NO_READRDY;
|
||||||
@@ -1228,8 +1229,9 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, 0,
|
ret = mtd_device_parse_register(info->host[cs]->mtd, NULL,
|
||||||
pdata->parts[cs], pdata->nr_parts[cs]);
|
NULL, pdata->parts[cs],
|
||||||
|
pdata->nr_parts[cs]);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
probe_success = 1;
|
probe_success = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -891,6 +891,7 @@ int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
|
|||||||
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
|
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
|
||||||
chip->ecc.size = R852_DMA_LEN;
|
chip->ecc.size = R852_DMA_LEN;
|
||||||
chip->ecc.bytes = SM_OOB_SIZE;
|
chip->ecc.bytes = SM_OOB_SIZE;
|
||||||
|
chip->ecc.strength = 2;
|
||||||
chip->ecc.hwctl = r852_ecc_hwctl;
|
chip->ecc.hwctl = r852_ecc_hwctl;
|
||||||
chip->ecc.calculate = r852_ecc_calculate;
|
chip->ecc.calculate = r852_ecc_calculate;
|
||||||
chip->ecc.correct = r852_ecc_correct;
|
chip->ecc.correct = r852_ecc_correct;
|
||||||
|
|||||||
@@ -527,6 +527,7 @@ static int __init rtc_from4_init(void)
|
|||||||
this->ecc.mode = NAND_ECC_HW_SYNDROME;
|
this->ecc.mode = NAND_ECC_HW_SYNDROME;
|
||||||
this->ecc.size = 512;
|
this->ecc.size = 512;
|
||||||
this->ecc.bytes = 8;
|
this->ecc.bytes = 8;
|
||||||
|
this->ecc.strength = 3;
|
||||||
/* return the status of extra status and ECC checks */
|
/* return the status of extra status and ECC checks */
|
||||||
this->errstat = rtc_from4_errstat;
|
this->errstat = rtc_from4_errstat;
|
||||||
/* set the nand_oobinfo to support FPGA H/W error detection */
|
/* set the nand_oobinfo to support FPGA H/W error detection */
|
||||||
|
|||||||
@@ -751,8 +751,8 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
|
|||||||
if (set)
|
if (set)
|
||||||
mtd->mtd.name = set->name;
|
mtd->mtd.name = set->name;
|
||||||
|
|
||||||
return mtd_device_parse_register(&mtd->mtd, NULL, 0,
|
return mtd_device_parse_register(&mtd->mtd, NULL, NULL,
|
||||||
set->partitions, set->nr_partitions);
|
set->partitions, set->nr_partitions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -823,6 +823,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
|
|||||||
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
|
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
|
||||||
chip->ecc.correct = s3c2410_nand_correct_data;
|
chip->ecc.correct = s3c2410_nand_correct_data;
|
||||||
chip->ecc.mode = NAND_ECC_HW;
|
chip->ecc.mode = NAND_ECC_HW;
|
||||||
|
chip->ecc.strength = 1;
|
||||||
|
|
||||||
switch (info->cpu_type) {
|
switch (info->cpu_type) {
|
||||||
case TYPE_S3C2410:
|
case TYPE_S3C2410:
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include <linux/mtd/mtd.h>
|
#include <linux/mtd/mtd.h>
|
||||||
@@ -283,7 +284,7 @@ static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
|
|||||||
static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
|
static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
|
||||||
{
|
{
|
||||||
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
||||||
uint32_t flcmncr_val = readl(FLCMNCR(flctl)) & ~SEL_16BIT;
|
uint32_t flcmncr_val = flctl->flcmncr_base & ~SEL_16BIT;
|
||||||
uint32_t flcmdcr_val, addr_len_bytes = 0;
|
uint32_t flcmdcr_val, addr_len_bytes = 0;
|
||||||
|
|
||||||
/* Set SNAND bit if page size is 2048byte */
|
/* Set SNAND bit if page size is 2048byte */
|
||||||
@@ -303,6 +304,7 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
|
|||||||
break;
|
break;
|
||||||
case NAND_CMD_READ0:
|
case NAND_CMD_READ0:
|
||||||
case NAND_CMD_READOOB:
|
case NAND_CMD_READOOB:
|
||||||
|
case NAND_CMD_RNDOUT:
|
||||||
addr_len_bytes = flctl->rw_ADRCNT;
|
addr_len_bytes = flctl->rw_ADRCNT;
|
||||||
flcmdcr_val |= CDSRC_E;
|
flcmdcr_val |= CDSRC_E;
|
||||||
if (flctl->chip.options & NAND_BUSWIDTH_16)
|
if (flctl->chip.options & NAND_BUSWIDTH_16)
|
||||||
@@ -320,6 +322,7 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
|
|||||||
break;
|
break;
|
||||||
case NAND_CMD_READID:
|
case NAND_CMD_READID:
|
||||||
flcmncr_val &= ~SNAND_E;
|
flcmncr_val &= ~SNAND_E;
|
||||||
|
flcmdcr_val |= CDSRC_E;
|
||||||
addr_len_bytes = ADRCNT_1;
|
addr_len_bytes = ADRCNT_1;
|
||||||
break;
|
break;
|
||||||
case NAND_CMD_STATUS:
|
case NAND_CMD_STATUS:
|
||||||
@@ -513,6 +516,8 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
|||||||
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
||||||
uint32_t read_cmd = 0;
|
uint32_t read_cmd = 0;
|
||||||
|
|
||||||
|
pm_runtime_get_sync(&flctl->pdev->dev);
|
||||||
|
|
||||||
flctl->read_bytes = 0;
|
flctl->read_bytes = 0;
|
||||||
if (command != NAND_CMD_PAGEPROG)
|
if (command != NAND_CMD_PAGEPROG)
|
||||||
flctl->index = 0;
|
flctl->index = 0;
|
||||||
@@ -525,7 +530,6 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
|||||||
execmd_read_page_sector(mtd, page_addr);
|
execmd_read_page_sector(mtd, page_addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
empty_fifo(flctl);
|
|
||||||
if (flctl->page_size)
|
if (flctl->page_size)
|
||||||
set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
|
set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
|
||||||
| command);
|
| command);
|
||||||
@@ -547,7 +551,6 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
empty_fifo(flctl);
|
|
||||||
if (flctl->page_size) {
|
if (flctl->page_size) {
|
||||||
set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
|
set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8)
|
||||||
| NAND_CMD_READ0);
|
| NAND_CMD_READ0);
|
||||||
@@ -559,15 +562,35 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
|||||||
flctl->read_bytes = mtd->oobsize;
|
flctl->read_bytes = mtd->oobsize;
|
||||||
goto read_normal_exit;
|
goto read_normal_exit;
|
||||||
|
|
||||||
case NAND_CMD_READID:
|
case NAND_CMD_RNDOUT:
|
||||||
empty_fifo(flctl);
|
if (flctl->hwecc)
|
||||||
set_cmd_regs(mtd, command, command);
|
break;
|
||||||
set_addr(mtd, 0, 0);
|
|
||||||
|
|
||||||
flctl->read_bytes = 4;
|
if (flctl->page_size)
|
||||||
|
set_cmd_regs(mtd, command, (NAND_CMD_RNDOUTSTART << 8)
|
||||||
|
| command);
|
||||||
|
else
|
||||||
|
set_cmd_regs(mtd, command, command);
|
||||||
|
|
||||||
|
set_addr(mtd, column, 0);
|
||||||
|
|
||||||
|
flctl->read_bytes = mtd->writesize + mtd->oobsize - column;
|
||||||
|
goto read_normal_exit;
|
||||||
|
|
||||||
|
case NAND_CMD_READID:
|
||||||
|
set_cmd_regs(mtd, command, command);
|
||||||
|
|
||||||
|
/* READID is always performed using an 8-bit bus */
|
||||||
|
if (flctl->chip.options & NAND_BUSWIDTH_16)
|
||||||
|
column <<= 1;
|
||||||
|
set_addr(mtd, column, 0);
|
||||||
|
|
||||||
|
flctl->read_bytes = 8;
|
||||||
writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
|
writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
|
||||||
|
empty_fifo(flctl);
|
||||||
start_translation(flctl);
|
start_translation(flctl);
|
||||||
read_datareg(flctl, 0); /* read and end */
|
read_fiforeg(flctl, flctl->read_bytes, 0);
|
||||||
|
wait_completion(flctl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAND_CMD_ERASE1:
|
case NAND_CMD_ERASE1:
|
||||||
@@ -650,29 +673,55 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return;
|
goto runtime_exit;
|
||||||
|
|
||||||
read_normal_exit:
|
read_normal_exit:
|
||||||
writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
|
writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */
|
||||||
|
empty_fifo(flctl);
|
||||||
start_translation(flctl);
|
start_translation(flctl);
|
||||||
read_fiforeg(flctl, flctl->read_bytes, 0);
|
read_fiforeg(flctl, flctl->read_bytes, 0);
|
||||||
wait_completion(flctl);
|
wait_completion(flctl);
|
||||||
|
runtime_exit:
|
||||||
|
pm_runtime_put_sync(&flctl->pdev->dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
|
static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
|
||||||
{
|
{
|
||||||
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
||||||
uint32_t flcmncr_val = readl(FLCMNCR(flctl));
|
int ret;
|
||||||
|
|
||||||
switch (chipnr) {
|
switch (chipnr) {
|
||||||
case -1:
|
case -1:
|
||||||
flcmncr_val &= ~CE0_ENABLE;
|
flctl->flcmncr_base &= ~CE0_ENABLE;
|
||||||
writel(flcmncr_val, FLCMNCR(flctl));
|
|
||||||
|
pm_runtime_get_sync(&flctl->pdev->dev);
|
||||||
|
writel(flctl->flcmncr_base, FLCMNCR(flctl));
|
||||||
|
|
||||||
|
if (flctl->qos_request) {
|
||||||
|
dev_pm_qos_remove_request(&flctl->pm_qos);
|
||||||
|
flctl->qos_request = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pm_runtime_put_sync(&flctl->pdev->dev);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
flcmncr_val |= CE0_ENABLE;
|
flctl->flcmncr_base |= CE0_ENABLE;
|
||||||
writel(flcmncr_val, FLCMNCR(flctl));
|
|
||||||
|
if (!flctl->qos_request) {
|
||||||
|
ret = dev_pm_qos_add_request(&flctl->pdev->dev,
|
||||||
|
&flctl->pm_qos, 100);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(&flctl->pdev->dev,
|
||||||
|
"PM QoS request failed: %d\n", ret);
|
||||||
|
flctl->qos_request = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flctl->holden) {
|
||||||
|
pm_runtime_get_sync(&flctl->pdev->dev);
|
||||||
|
writel(HOLDEN, FLHOLDCR(flctl));
|
||||||
|
pm_runtime_put_sync(&flctl->pdev->dev);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
@@ -730,11 +779,6 @@ static int flctl_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flctl_register_init(struct sh_flctl *flctl, unsigned long val)
|
|
||||||
{
|
|
||||||
writel(val, FLCMNCR(flctl));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int flctl_chip_init_tail(struct mtd_info *mtd)
|
static int flctl_chip_init_tail(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
||||||
@@ -781,13 +825,13 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
|
|||||||
|
|
||||||
chip->ecc.size = 512;
|
chip->ecc.size = 512;
|
||||||
chip->ecc.bytes = 10;
|
chip->ecc.bytes = 10;
|
||||||
|
chip->ecc.strength = 4;
|
||||||
chip->ecc.read_page = flctl_read_page_hwecc;
|
chip->ecc.read_page = flctl_read_page_hwecc;
|
||||||
chip->ecc.write_page = flctl_write_page_hwecc;
|
chip->ecc.write_page = flctl_write_page_hwecc;
|
||||||
chip->ecc.mode = NAND_ECC_HW;
|
chip->ecc.mode = NAND_ECC_HW;
|
||||||
|
|
||||||
/* 4 symbols ECC enabled */
|
/* 4 symbols ECC enabled */
|
||||||
writel(readl(FLCMNCR(flctl)) | _4ECCEN | ECCPOS2 | ECCPOS_02,
|
flctl->flcmncr_base |= _4ECCEN | ECCPOS2 | ECCPOS_02;
|
||||||
FLCMNCR(flctl));
|
|
||||||
} else {
|
} else {
|
||||||
chip->ecc.mode = NAND_ECC_SOFT;
|
chip->ecc.mode = NAND_ECC_SOFT;
|
||||||
}
|
}
|
||||||
@@ -819,13 +863,13 @@ static int __devinit flctl_probe(struct platform_device *pdev)
|
|||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
dev_err(&pdev->dev, "failed to get I/O memory\n");
|
dev_err(&pdev->dev, "failed to get I/O memory\n");
|
||||||
goto err;
|
goto err_iomap;
|
||||||
}
|
}
|
||||||
|
|
||||||
flctl->reg = ioremap(res->start, resource_size(res));
|
flctl->reg = ioremap(res->start, resource_size(res));
|
||||||
if (flctl->reg == NULL) {
|
if (flctl->reg == NULL) {
|
||||||
dev_err(&pdev->dev, "failed to remap I/O memory\n");
|
dev_err(&pdev->dev, "failed to remap I/O memory\n");
|
||||||
goto err;
|
goto err_iomap;
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, flctl);
|
platform_set_drvdata(pdev, flctl);
|
||||||
@@ -833,9 +877,9 @@ static int __devinit flctl_probe(struct platform_device *pdev)
|
|||||||
nand = &flctl->chip;
|
nand = &flctl->chip;
|
||||||
flctl_mtd->priv = nand;
|
flctl_mtd->priv = nand;
|
||||||
flctl->pdev = pdev;
|
flctl->pdev = pdev;
|
||||||
|
flctl->flcmncr_base = pdata->flcmncr_val;
|
||||||
flctl->hwecc = pdata->has_hwecc;
|
flctl->hwecc = pdata->has_hwecc;
|
||||||
|
flctl->holden = pdata->use_holden;
|
||||||
flctl_register_init(flctl, pdata->flcmncr_val);
|
|
||||||
|
|
||||||
nand->options = NAND_NO_AUTOINCR;
|
nand->options = NAND_NO_AUTOINCR;
|
||||||
|
|
||||||
@@ -855,23 +899,28 @@ static int __devinit flctl_probe(struct platform_device *pdev)
|
|||||||
nand->read_word = flctl_read_word;
|
nand->read_word = flctl_read_word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
pm_runtime_resume(&pdev->dev);
|
||||||
|
|
||||||
ret = nand_scan_ident(flctl_mtd, 1, NULL);
|
ret = nand_scan_ident(flctl_mtd, 1, NULL);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err_chip;
|
||||||
|
|
||||||
ret = flctl_chip_init_tail(flctl_mtd);
|
ret = flctl_chip_init_tail(flctl_mtd);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err_chip;
|
||||||
|
|
||||||
ret = nand_scan_tail(flctl_mtd);
|
ret = nand_scan_tail(flctl_mtd);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err_chip;
|
||||||
|
|
||||||
mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
|
mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err_chip:
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
err_iomap:
|
||||||
kfree(flctl);
|
kfree(flctl);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -881,6 +930,7 @@ static int __devexit flctl_remove(struct platform_device *pdev)
|
|||||||
struct sh_flctl *flctl = platform_get_drvdata(pdev);
|
struct sh_flctl *flctl = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
nand_release(&flctl->mtd);
|
nand_release(&flctl->mtd);
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
kfree(flctl);
|
kfree(flctl);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user