提交 0fc7e746 编写于 作者: L Linus Torvalds

Merge tag 'mtd/for-4.16' of git://git.infradead.org/linux-mtd

Pull MTD updates from Boris Brezillon:
 "MTD core changes:
   - Rework core functions to avoid duplicating generic checks in
     NAND/OneNAND sub-layers
   - Update the MAINTAINERS entry to reflect the fact that MTD
     maintainers now use a single git tree

  MTD driver changes:
   - CFI: use macros instead of inline functions to limit stack usage
     and make KASAN happy

  NAND core changes:
   - Fix NAND_CMD_NONE handling in nand_command[_lp]() hooks
   - Introduce the ->exec_op() infrastructure
   - Rework NAND buffers handling
   - Fix ECC requirements for K9F4G08U0D
   - Fix nand_do_read_oob() to return the number of bitflips
   - Mark K9F1G08U0E as not supporting subpage writes

  NAND driver changes:
   - MTK: Rework the driver to support new IP versions
   - OMAP OneNAND: Full rework to use new APIs (libgpio, dmaengine) and
     fix DT support
   - Marvell: Add a new driver to replace the pxa3xx one

  SPI NOR core changes:
   - Add support to new ISSI and Cypress/Spansion memory parts.
   - Fix support of Micron memories by checking error bits in the FSR.
   - Fix update of block-protection bits by reading back the SR.
   - Restore the internal state of the SPI flash memory when removing
     the device.

  SPI NOR driver changes:
   - Maintenance for Freescale, Intel and Metiatek drivers.
   - Add support of the direct access mode for the Cadence QSPI
     controller"

* tag 'mtd/for-4.16' of git://git.infradead.org/linux-mtd: (93 commits)
  mtd: nand: sunxi: Fix ECC strength choice
  mtd: nand: gpmi: Fix subpage reads
  mtd: nand: Fix build issues due to an anonymous union
  mtd: nand: marvell: Fix missing memory allocation modifier
  mtd: nand: marvell: remove redundant variable 'oob_len'
  mtd: nand: marvell: fix spelling mistake: "suceed"-> "succeed"
  mtd: onenand: omap2: Remove redundant dev_err call in omap2_onenand_probe()
  mtd: Remove duplicate checks on mtd_oob_ops parameter
  mtd: Fallback to ->_read/write_oob() when ->_read/write() is missing
  mtd: mtdpart: Make ECC stat handling consistent
  mtd: onenand: omap2: print resource using %pR format string
  mtd: mtk-nor: modify functions' name more generally
  mtd: onenand: samsung: remove incorrect __iomem annotation
  MAINTAINERS: Add entry for Marvell NAND controller driver
  ARM: OMAP2+: Remove gpmc-onenand
  mtd: onenand: omap2: Configure driver from DT
  mtd: onenand: omap2: Decouple DMA enabling from INT pin availability
  mtd: onenand: omap2: Do not make delay for GPIO OMAP3 specific
  mtd: onenand: omap2: Convert to use dmaengine for memcpy
  mtd: onenand: omap2: Unify OMAP2 and OMAP3 DMA implementation
  ...
...@@ -12,7 +12,7 @@ Required properties: ...@@ -12,7 +12,7 @@ Required properties:
- reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory"
- interrupts : Should contain the interrupt for the device - interrupts : Should contain the interrupt for the device
- clocks : The clocks needed by the QuadSPI controller - clocks : The clocks needed by the QuadSPI controller
- clock-names : the name of the clocks - clock-names : Should contain the name of the clocks: "qspi_en" and "qspi".
Optional properties: Optional properties:
- fsl,qspi-has-second-chip: The controller has two buses, bus A and bus B. - fsl,qspi-has-second-chip: The controller has two buses, bus A and bus B.
......
...@@ -9,13 +9,14 @@ Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt ...@@ -9,13 +9,14 @@ Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
Required properties: Required properties:
- compatible: "ti,omap2-onenand"
- reg: The CS line the peripheral is connected to - reg: The CS line the peripheral is connected to
- gpmc,device-width Width of the ONENAND device connected to the GPMC - gpmc,device-width: Width of the ONENAND device connected to the GPMC
in bytes. Must be 1 or 2. in bytes. Must be 1 or 2.
Optional properties: Optional properties:
- dma-channel: DMA Channel index - int-gpios: GPIO specifier for the INT pin.
For inline partition table parsing (optional): For inline partition table parsing (optional):
...@@ -35,6 +36,7 @@ Example for an OMAP3430 board: ...@@ -35,6 +36,7 @@ Example for an OMAP3430 board:
#size-cells = <1>; #size-cells = <1>;
onenand@0 { onenand@0 {
compatible = "ti,omap2-onenand";
reg = <0 0 0>; /* CS0, offset 0 */ reg = <0 0 0>; /* CS0, offset 0 */
gpmc,device-width = <2>; gpmc,device-width = <2>;
......
Marvell NAND Flash Controller (NFC)
Required properties:
- compatible: can be one of the following:
* "marvell,armada-8k-nand-controller"
* "marvell,armada370-nand-controller"
* "marvell,pxa3xx-nand-controller"
* "marvell,armada-8k-nand" (deprecated)
* "marvell,armada370-nand" (deprecated)
* "marvell,pxa3xx-nand" (deprecated)
Compatibles marked deprecated support only the old bindings described
at the bottom.
- reg: NAND flash controller memory area.
- #address-cells: shall be set to 1. Encode the NAND CS.
- #size-cells: shall be set to 0.
- interrupts: shall define the NAND controller interrupt.
- clocks: shall reference the NAND controller clock.
- marvell,system-controller: Set to retrieve the syscon node that handles
NAND controller related registers (only required with the
"marvell,armada-8k-nand[-controller]" compatibles).
Optional properties:
- label: see partition.txt. New platforms shall omit this property.
- dmas: shall reference DMA channel associated to the NAND controller.
This property is only used with "marvell,pxa3xx-nand[-controller]"
compatible strings.
- dma-names: shall be "rxtx".
This property is only used with "marvell,pxa3xx-nand[-controller]"
compatible strings.
Optional children nodes:
Children nodes represent the available NAND chips.
Required properties:
- reg: shall contain the native Chip Select ids (0-3).
- nand-rb: see nand.txt (0-1).
Optional properties:
- marvell,nand-keep-config: orders the driver not to take the timings
from the core and leaving them completely untouched. Bootloader
timings will then be used.
- label: MTD name.
- nand-on-flash-bbt: see nand.txt.
- nand-ecc-mode: see nand.txt. Will use hardware ECC if not specified.
- nand-ecc-algo: see nand.txt. This property is essentially useful when
not using hardware ECC. Howerver, it may be added when using hardware
ECC for clarification but will be ignored by the driver because ECC
mode is chosen depending on the page size and the strength required by
the NAND chip. This value may be overwritten with nand-ecc-strength
property.
- nand-ecc-strength: see nand.txt.
- nand-ecc-step-size: see nand.txt. Marvell's NAND flash controller does
use fixed strength (1-bit for Hamming, 16-bit for BCH), so the actual
step size will shrink or grow in order to fit the required strength.
Step sizes are not completely random for all and follow certain
patterns described in AN-379, "Marvell SoC NFC ECC".
See Documentation/devicetree/bindings/mtd/nand.txt for more details on
generic bindings.
Example:
nand_controller: nand-controller@d0000 {
compatible = "marvell,armada370-nand-controller";
reg = <0xd0000 0x54>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&coredivclk 0>;
nand@0 {
reg = <0>;
label = "main-storage";
nand-rb = <0>;
nand-ecc-mode = "hw";
marvell,nand-keep-config;
nand-on-flash-bbt;
nand-ecc-strength = <4>;
nand-ecc-step-size = <512>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "Rootfs";
reg = <0x00000000 0x40000000>;
};
};
};
};
Note on legacy bindings: One can find, in not-updated device trees,
bindings slightly different than described above with other properties
described below as well as the partitions node at the root of a so
called "nand" node (without clear controller/chip separation).
Legacy properties:
- marvell,nand-enable-arbiter: To enable the arbiter, all boards blindly
used it, this bit was set by the bootloader for many boards and even if
it is marked reserved in several datasheets, it might be needed to set
it (otherwise it is harmless) so whether or not this property is set,
the bit is selected by the driver.
- num-cs: Number of chip-select lines to use, all boards blindly set 1
to this and for a reason, other values would have failed. The value of
this property is ignored.
Example:
nand0: nand@43100000 {
compatible = "marvell,pxa3xx-nand";
reg = <0x43100000 90>;
interrupts = <45>;
dmas = <&pdma 97 0>;
dma-names = "rxtx";
#address-cells = <1>;
marvell,nand-keep-config;
marvell,nand-enable-arbiter;
num-cs = <1>;
/* Partitions (optional) */
};
...@@ -12,8 +12,10 @@ tree nodes. ...@@ -12,8 +12,10 @@ tree nodes.
The first part of NFC is NAND Controller Interface (NFI) HW. The first part of NFC is NAND Controller Interface (NFI) HW.
Required NFI properties: Required NFI properties:
- compatible: Should be one of "mediatek,mt2701-nfc", - compatible: Should be one of
"mediatek,mt2712-nfc". "mediatek,mt2701-nfc",
"mediatek,mt2712-nfc",
"mediatek,mt7622-nfc".
- reg: Base physical address and size of NFI. - reg: Base physical address and size of NFI.
- interrupts: Interrupts of NFI. - interrupts: Interrupts of NFI.
- clocks: NFI required clocks. - clocks: NFI required clocks.
...@@ -142,7 +144,10 @@ Example: ...@@ -142,7 +144,10 @@ Example:
============== ==============
Required BCH properties: Required BCH properties:
- compatible: Should be one of "mediatek,mt2701-ecc", "mediatek,mt2712-ecc". - compatible: Should be one of
"mediatek,mt2701-ecc",
"mediatek,mt2712-ecc",
"mediatek,mt7622-ecc".
- reg: Base physical address and size of ECC. - reg: Base physical address and size of ECC.
- interrupts: Interrupts of ECC. - interrupts: Interrupts of ECC.
- clocks: ECC required clocks. - clocks: ECC required clocks.
......
...@@ -43,6 +43,7 @@ Optional NAND chip properties: ...@@ -43,6 +43,7 @@ Optional NAND chip properties:
This is particularly useful when only the in-band area is This is particularly useful when only the in-band area is
used by the upper layers, and you want to make your NAND used by the upper layers, and you want to make your NAND
as reliable as possible. as reliable as possible.
- nand-rb: shall contain the native Ready/Busy ids.
The ECC strength and ECC step size properties define the correction capability The ECC strength and ECC step size properties define the correction capability
of a controller. Together, they say a controller can correct "{strength} bit of a controller. Together, they say a controller can correct "{strength} bit
......
...@@ -60,3 +60,6 @@ The main API is spi_nor_scan(). Before you call the hook, a driver should ...@@ -60,3 +60,6 @@ The main API is spi_nor_scan(). Before you call the hook, a driver should
initialize the necessary fields for spi_nor{}. Please see initialize the necessary fields for spi_nor{}. Please see
drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c
when you want to write a new driver for a SPI NOR controller. when you want to write a new driver for a SPI NOR controller.
Another API is spi_nor_restore(), this is used to restore the status of SPI
flash chip such as addressing mode. Call it whenever detach the driver from
device or reboot the system.
...@@ -2392,13 +2392,6 @@ F: Documentation/devicetree/bindings/input/atmel,maxtouch.txt ...@@ -2392,13 +2392,6 @@ F: Documentation/devicetree/bindings/input/atmel,maxtouch.txt
F: drivers/input/touchscreen/atmel_mxt_ts.c F: drivers/input/touchscreen/atmel_mxt_ts.c
F: include/linux/platform_data/atmel_mxt_ts.h F: include/linux/platform_data/atmel_mxt_ts.h
ATMEL NAND DRIVER
M: Wenyou Yang <wenyou.yang@atmel.com>
M: Josh Wu <rainyfeeling@outlook.com>
L: linux-mtd@lists.infradead.org
S: Supported
F: drivers/mtd/nand/atmel/*
ATMEL SAMA5D2 ADC DRIVER ATMEL SAMA5D2 ADC DRIVER
M: Ludovic Desroches <ludovic.desroches@microchip.com> M: Ludovic Desroches <ludovic.desroches@microchip.com>
L: linux-iio@vger.kernel.org L: linux-iio@vger.kernel.org
...@@ -8406,6 +8399,13 @@ L: linux-wireless@vger.kernel.org ...@@ -8406,6 +8399,13 @@ L: linux-wireless@vger.kernel.org
S: Odd Fixes S: Odd Fixes
F: drivers/net/wireless/marvell/mwl8k.c F: drivers/net/wireless/marvell/mwl8k.c
MARVELL NAND CONTROLLER DRIVER
M: Miquel Raynal <miquel.raynal@free-electrons.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/nand/marvell_nand.c
F: Documentation/devicetree/bindings/mtd/marvell-nand.txt
MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
M: Nicolas Pitre <nico@fluxnic.net> M: Nicolas Pitre <nico@fluxnic.net>
S: Odd Fixes S: Odd Fixes
...@@ -8953,7 +8953,7 @@ L: linux-mtd@lists.infradead.org ...@@ -8953,7 +8953,7 @@ L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/ W: http://www.linux-mtd.infradead.org/
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
T: git git://git.infradead.org/linux-mtd.git master T: git git://git.infradead.org/linux-mtd.git master
T: git git://git.infradead.org/l2-mtd.git master T: git git://git.infradead.org/linux-mtd.git mtd/next
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/mtd/ F: Documentation/devicetree/bindings/mtd/
F: drivers/mtd/ F: drivers/mtd/
...@@ -9042,6 +9042,14 @@ F: drivers/media/platform/atmel/atmel-isc.c ...@@ -9042,6 +9042,14 @@ F: drivers/media/platform/atmel/atmel-isc.c
F: drivers/media/platform/atmel/atmel-isc-regs.h F: drivers/media/platform/atmel/atmel-isc-regs.h
F: devicetree/bindings/media/atmel-isc.txt F: devicetree/bindings/media/atmel-isc.txt
MICROCHIP / ATMEL NAND DRIVER
M: Wenyou Yang <wenyou.yang@microchip.com>
M: Josh Wu <rainyfeeling@outlook.com>
L: linux-mtd@lists.infradead.org
S: Supported
F: drivers/mtd/nand/atmel/*
F: Documentation/devicetree/bindings/mtd/atmel-nand.txt
MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER
M: Woojung Huh <Woojung.Huh@microchip.com> M: Woojung Huh <Woojung.Huh@microchip.com>
M: Microchip Linux Driver Support <UNGLinuxDriver@microchip.com> M: Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
...@@ -9342,7 +9350,7 @@ L: linux-mtd@lists.infradead.org ...@@ -9342,7 +9350,7 @@ L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/ W: http://www.linux-mtd.infradead.org/
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
T: git git://git.infradead.org/linux-mtd.git nand/fixes T: git git://git.infradead.org/linux-mtd.git nand/fixes
T: git git://git.infradead.org/l2-mtd.git nand/next T: git git://git.infradead.org/linux-mtd.git nand/next
S: Maintained S: Maintained
F: drivers/mtd/nand/ F: drivers/mtd/nand/
F: include/linux/mtd/*nand*.h F: include/linux/mtd/*nand*.h
...@@ -12787,7 +12795,7 @@ L: linux-mtd@lists.infradead.org ...@@ -12787,7 +12795,7 @@ L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/ W: http://www.linux-mtd.infradead.org/
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
T: git git://git.infradead.org/linux-mtd.git spi-nor/fixes T: git git://git.infradead.org/linux-mtd.git spi-nor/fixes
T: git git://git.infradead.org/l2-mtd.git spi-nor/next T: git git://git.infradead.org/linux-mtd.git spi-nor/next
S: Maintained S: Maintained
F: drivers/mtd/spi-nor/ F: drivers/mtd/spi-nor/
F: include/linux/mtd/spi-nor.h F: include/linux/mtd/spi-nor.h
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
onenand@0,0 { onenand@0,0 {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
compatible = "ti,omap2-onenand";
reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */ reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */
gpmc,sync-read; gpmc,sync-read;
......
...@@ -147,32 +147,32 @@ ...@@ -147,32 +147,32 @@
gpmc,sync-read; gpmc,sync-read;
gpmc,sync-write; gpmc,sync-write;
gpmc,burst-length = <16>; gpmc,burst-length = <16>;
gpmc,burst-read;
gpmc,burst-wrap; gpmc,burst-wrap;
gpmc,burst-read;
gpmc,burst-write; gpmc,burst-write;
gpmc,device-width = <2>; /* GPMC_DEVWIDTH_16BIT */ gpmc,device-width = <2>; /* GPMC_DEVWIDTH_16BIT */
gpmc,mux-add-data = <2>; /* GPMC_MUX_AD */ gpmc,mux-add-data = <2>; /* GPMC_MUX_AD */
gpmc,cs-on-ns = <0>; gpmc,cs-on-ns = <0>;
gpmc,cs-rd-off-ns = <87>; gpmc,cs-rd-off-ns = <96>;
gpmc,cs-wr-off-ns = <87>; gpmc,cs-wr-off-ns = <96>;
gpmc,adv-on-ns = <0>; gpmc,adv-on-ns = <0>;
gpmc,adv-rd-off-ns = <10>; gpmc,adv-rd-off-ns = <12>;
gpmc,adv-wr-off-ns = <10>; gpmc,adv-wr-off-ns = <12>;
gpmc,oe-on-ns = <15>; gpmc,oe-on-ns = <18>;
gpmc,oe-off-ns = <87>; gpmc,oe-off-ns = <96>;
gpmc,we-on-ns = <0>; gpmc,we-on-ns = <0>;
gpmc,we-off-ns = <87>; gpmc,we-off-ns = <96>;
gpmc,rd-cycle-ns = <112>; gpmc,rd-cycle-ns = <114>;
gpmc,wr-cycle-ns = <112>; gpmc,wr-cycle-ns = <114>;
gpmc,access-ns = <81>; gpmc,access-ns = <90>;
gpmc,page-burst-access-ns = <15>; gpmc,page-burst-access-ns = <12>;
gpmc,bus-turnaround-ns = <0>; gpmc,bus-turnaround-ns = <0>;
gpmc,cycle2cycle-delay-ns = <0>; gpmc,cycle2cycle-delay-ns = <0>;
gpmc,wait-monitoring-ns = <0>; gpmc,wait-monitoring-ns = <0>;
gpmc,clk-activation-ns = <5>; gpmc,clk-activation-ns = <6>;
gpmc,wr-data-mux-bus-ns = <30>; gpmc,wr-data-mux-bus-ns = <30>;
gpmc,wr-access-ns = <81>; gpmc,wr-access-ns = <90>;
gpmc,sync-clk-ps = <15000>; gpmc,sync-clk-ps = <12000>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
......
...@@ -838,6 +838,7 @@ ...@@ -838,6 +838,7 @@
onenand@0,0 { onenand@0,0 {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
compatible = "ti,omap2-onenand";
reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */ reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */
gpmc,sync-read; gpmc,sync-read;
......
...@@ -367,6 +367,7 @@ ...@@ -367,6 +367,7 @@
onenand@0,0 { onenand@0,0 {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
compatible = "ti,omap2-onenand";
reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */ reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */
gpmc,sync-read; gpmc,sync-read;
......
...@@ -154,6 +154,7 @@ ...@@ -154,6 +154,7 @@
linux,mtd-name= "samsung,kfm2g16q2m-deb8"; linux,mtd-name= "samsung,kfm2g16q2m-deb8";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
compatible = "ti,omap2-onenand";
reg = <2 0 0x20000>; /* CS2, offset 0, IO size 4 */ reg = <2 0 0x20000>; /* CS2, offset 0, IO size 4 */
gpmc,device-width = <2>; gpmc,device-width = <2>;
......
...@@ -57,7 +57,7 @@ CONFIG_MTD_CFI_STAA=y ...@@ -57,7 +57,7 @@ CONFIG_MTD_CFI_STAA=y
CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_PHYSMAP_OF=y
CONFIG_MTD_M25P80=y CONFIG_MTD_M25P80=y
CONFIG_MTD_NAND=y CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_PXA3xx=y CONFIG_MTD_NAND_MARVELL=y
CONFIG_MTD_SPI_NOR=y CONFIG_MTD_SPI_NOR=y
CONFIG_SRAM=y CONFIG_SRAM=y
CONFIG_MTD_UBI=y CONFIG_MTD_UBI=y
......
...@@ -232,6 +232,3 @@ obj-y += $(omap-hsmmc-m) $(omap-hsmmc-y) ...@@ -232,6 +232,3 @@ obj-y += $(omap-hsmmc-m) $(omap-hsmmc-y)
obj-y += omap_phy_internal.o obj-y += omap_phy_internal.o
obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o
onenand-$(CONFIG_MTD_ONENAND_OMAP2) := gpmc-onenand.o
obj-y += $(onenand-m) $(onenand-y)
/*
* linux/arch/arm/mach-omap2/gpmc-onenand.c
*
* Copyright (C) 2006 - 2009 Nokia Corporation
* Contacts: Juha Yrjola
* Tony Lindgren
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/mtd/onenand_regs.h>
#include <linux/io.h>
#include <linux/omap-gpmc.h>
#include <linux/platform_data/mtd-onenand-omap2.h>
#include <linux/err.h>
#include <asm/mach/flash.h>
#include "soc.h"
#define ONENAND_IO_SIZE SZ_128K
#define ONENAND_FLAG_SYNCREAD (1 << 0)
#define ONENAND_FLAG_SYNCWRITE (1 << 1)
#define ONENAND_FLAG_HF (1 << 2)
#define ONENAND_FLAG_VHF (1 << 3)
static unsigned onenand_flags;
static unsigned latency;
static struct omap_onenand_platform_data *gpmc_onenand_data;
static struct resource gpmc_onenand_resource = {
.flags = IORESOURCE_MEM,
};
static struct platform_device gpmc_onenand_device = {
.name = "omap2-onenand",
.id = -1,
.num_resources = 1,
.resource = &gpmc_onenand_resource,
};
static struct gpmc_settings onenand_async = {
.device_width = GPMC_DEVWIDTH_16BIT,
.mux_add_data = GPMC_MUX_AD,
};
static struct gpmc_settings onenand_sync = {
.burst_read = true,
.burst_wrap = true,
.burst_len = GPMC_BURST_16,
.device_width = GPMC_DEVWIDTH_16BIT,
.mux_add_data = GPMC_MUX_AD,
.wait_pin = 0,
};
static void omap2_onenand_calc_async_timings(struct gpmc_timings *t)
{
struct gpmc_device_timings dev_t;
const int t_cer = 15;
const int t_avdp = 12;
const int t_aavdh = 7;
const int t_ce = 76;
const int t_aa = 76;
const int t_oe = 20;
const int t_cez = 20; /* max of t_cez, t_oez */
const int t_wpl = 40;
const int t_wph = 30;
memset(&dev_t, 0, sizeof(dev_t));
dev_t.t_avdp_r = max_t(int, t_avdp, t_cer) * 1000;
dev_t.t_avdp_w = dev_t.t_avdp_r;
dev_t.t_aavdh = t_aavdh * 1000;
dev_t.t_aa = t_aa * 1000;
dev_t.t_ce = t_ce * 1000;
dev_t.t_oe = t_oe * 1000;
dev_t.t_cez_r = t_cez * 1000;
dev_t.t_cez_w = dev_t.t_cez_r;
dev_t.t_wpl = t_wpl * 1000;
dev_t.t_wph = t_wph * 1000;
gpmc_calc_timings(t, &onenand_async, &dev_t);
}
static void omap2_onenand_set_async_mode(void __iomem *onenand_base)
{
u32 reg;
/* Ensure sync read and sync write are disabled */
reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
}
static void set_onenand_cfg(void __iomem *onenand_base)
{
u32 reg = ONENAND_SYS_CFG1_RDY | ONENAND_SYS_CFG1_INT;
reg |= (latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
ONENAND_SYS_CFG1_BL_16;
if (onenand_flags & ONENAND_FLAG_SYNCREAD)
reg |= ONENAND_SYS_CFG1_SYNC_READ;
else
reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
if (onenand_flags & ONENAND_FLAG_SYNCWRITE)
reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
else
reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
if (onenand_flags & ONENAND_FLAG_HF)
reg |= ONENAND_SYS_CFG1_HF;
else
reg &= ~ONENAND_SYS_CFG1_HF;
if (onenand_flags & ONENAND_FLAG_VHF)
reg |= ONENAND_SYS_CFG1_VHF;
else
reg &= ~ONENAND_SYS_CFG1_VHF;
writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
}
static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
void __iomem *onenand_base)
{
u16 ver = readw(onenand_base + ONENAND_REG_VERSION_ID);
int freq;
switch ((ver >> 4) & 0xf) {
case 0:
freq = 40;
break;
case 1:
freq = 54;
break;
case 2:
freq = 66;
break;
case 3:
freq = 83;
break;
case 4:
freq = 104;
break;
default:
pr_err("onenand rate not detected, bad GPMC async timings?\n");
freq = 0;
}
return freq;
}
static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t,
unsigned int flags,
int freq)
{
struct gpmc_device_timings dev_t;
const int t_cer = 15;
const int t_avdp = 12;
const int t_cez = 20; /* max of t_cez, t_oez */
const int t_wpl = 40;
const int t_wph = 30;
int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
int div, gpmc_clk_ns;
if (flags & ONENAND_SYNC_READ)
onenand_flags = ONENAND_FLAG_SYNCREAD;
else if (flags & ONENAND_SYNC_READWRITE)
onenand_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE;
switch (freq) {
case 104:
min_gpmc_clk_period = 9600; /* 104 MHz */
t_ces = 3;
t_avds = 4;
t_avdh = 2;
t_ach = 3;
t_aavdh = 6;
t_rdyo = 6;
break;
case 83:
min_gpmc_clk_period = 12000; /* 83 MHz */
t_ces = 5;
t_avds = 4;
t_avdh = 2;
t_ach = 6;
t_aavdh = 6;
t_rdyo = 9;
break;
case 66:
min_gpmc_clk_period = 15000; /* 66 MHz */
t_ces = 6;
t_avds = 5;
t_avdh = 2;
t_ach = 6;
t_aavdh = 6;
t_rdyo = 11;
break;
default:
min_gpmc_clk_period = 18500; /* 54 MHz */
t_ces = 7;
t_avds = 7;
t_avdh = 7;
t_ach = 9;
t_aavdh = 7;
t_rdyo = 15;
onenand_flags &= ~ONENAND_FLAG_SYNCWRITE;
break;
}
div = gpmc_calc_divider(min_gpmc_clk_period);
gpmc_clk_ns = gpmc_ticks_to_ns(div);
if (gpmc_clk_ns < 15) /* >66MHz */
onenand_flags |= ONENAND_FLAG_HF;
else
onenand_flags &= ~ONENAND_FLAG_HF;
if (gpmc_clk_ns < 12) /* >83MHz */
onenand_flags |= ONENAND_FLAG_VHF;
else
onenand_flags &= ~ONENAND_FLAG_VHF;
if (onenand_flags & ONENAND_FLAG_VHF)
latency = 8;
else if (onenand_flags & ONENAND_FLAG_HF)
latency = 6;
else if (gpmc_clk_ns >= 25) /* 40 MHz*/
latency = 3;
else
latency = 4;
/* Set synchronous read timings */
memset(&dev_t, 0, sizeof(dev_t));
if (onenand_flags & ONENAND_FLAG_SYNCREAD)
onenand_sync.sync_read = true;
if (onenand_flags & ONENAND_FLAG_SYNCWRITE) {
onenand_sync.sync_write = true;
onenand_sync.burst_write = true;
} else {
dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000;
dev_t.t_wpl = t_wpl * 1000;
dev_t.t_wph = t_wph * 1000;
dev_t.t_aavdh = t_aavdh * 1000;
}
dev_t.ce_xdelay = true;
dev_t.avd_xdelay = true;
dev_t.oe_xdelay = true;
dev_t.we_xdelay = true;
dev_t.clk = min_gpmc_clk_period;
dev_t.t_bacc = dev_t.clk;
dev_t.t_ces = t_ces * 1000;
dev_t.t_avds = t_avds * 1000;
dev_t.t_avdh = t_avdh * 1000;
dev_t.t_ach = t_ach * 1000;
dev_t.cyc_iaa = (latency + 1);
dev_t.t_cez_r = t_cez * 1000;
dev_t.t_cez_w = dev_t.t_cez_r;
dev_t.cyc_aavdh_oe = 1;
dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;
gpmc_calc_timings(t, &onenand_sync, &dev_t);
}
static int omap2_onenand_setup_async(void __iomem *onenand_base)
{
struct gpmc_timings t;
int ret;
/*
* Note that we need to keep sync_write set for the call to
* omap2_onenand_set_async_mode() to work to detect the onenand
* supported clock rate for the sync timings.
*/
if (gpmc_onenand_data->of_node) {
gpmc_read_settings_dt(gpmc_onenand_data->of_node,
&onenand_async);
if (onenand_async.sync_read || onenand_async.sync_write) {
if (onenand_async.sync_write)
gpmc_onenand_data->flags |=
ONENAND_SYNC_READWRITE;
else
gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
onenand_async.sync_read = false;
}
}
onenand_async.sync_write = true;
omap2_onenand_calc_async_timings(&t);
ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
if (ret < 0)
return ret;
ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t, &onenand_async);
if (ret < 0)
return ret;
omap2_onenand_set_async_mode(onenand_base);
return 0;
}
static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
{
int ret, freq = *freq_ptr;
struct gpmc_timings t;
if (!freq) {
/* Very first call freq is not known */
freq = omap2_onenand_get_freq(gpmc_onenand_data, onenand_base);
if (!freq)
return -ENODEV;
set_onenand_cfg(onenand_base);
}
if (gpmc_onenand_data->of_node) {
gpmc_read_settings_dt(gpmc_onenand_data->of_node,
&onenand_sync);
} else {
/*
* FIXME: Appears to be legacy code from initial ONENAND commit.
* Unclear what boards this is for and if this can be removed.
*/
if (!cpu_is_omap34xx())
onenand_sync.wait_on_read = true;
}
omap2_onenand_calc_sync_timings(&t, gpmc_onenand_data->flags, freq);
ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_sync);
if (ret < 0)
return ret;
ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t, &onenand_sync);
if (ret < 0)
return ret;
set_onenand_cfg(onenand_base);
*freq_ptr = freq;
return 0;
}
static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
{
struct device *dev = &gpmc_onenand_device.dev;
unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
int ret;
ret = omap2_onenand_setup_async(onenand_base);
if (ret) {
dev_err(dev, "unable to set to async mode\n");
return ret;
}
if (!(gpmc_onenand_data->flags & l))
return 0;
ret = omap2_onenand_setup_sync(onenand_base, freq_ptr);
if (ret)
dev_err(dev, "unable to set to sync mode\n");
return ret;
}
int gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
{
int err;
struct device *dev = &gpmc_onenand_device.dev;
gpmc_onenand_data = _onenand_data;
gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
if (cpu_is_omap24xx() &&
(gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) {
dev_warn(dev, "OneNAND using only SYNC_READ on 24xx\n");
gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE;
gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
}
if (cpu_is_omap34xx())
gpmc_onenand_data->flags |= ONENAND_IN_OMAP34XX;
else
gpmc_onenand_data->flags &= ~ONENAND_IN_OMAP34XX;
err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE,
(unsigned long *)&gpmc_onenand_resource.start);
if (err < 0) {
dev_err(dev, "Cannot request GPMC CS %d, error %d\n",
gpmc_onenand_data->cs, err);
return err;
}
gpmc_onenand_resource.end = gpmc_onenand_resource.start +
ONENAND_IO_SIZE - 1;
err = platform_device_register(&gpmc_onenand_device);
if (err) {
dev_err(dev, "Unable to register OneNAND device\n");
gpmc_cs_free(gpmc_onenand_data->cs);
}
return err;
}
...@@ -161,7 +161,7 @@ CONFIG_MTD_BLOCK=y ...@@ -161,7 +161,7 @@ CONFIG_MTD_BLOCK=y
CONFIG_MTD_M25P80=y CONFIG_MTD_M25P80=y
CONFIG_MTD_NAND=y CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_DENALI_DT=y CONFIG_MTD_NAND_DENALI_DT=y
CONFIG_MTD_NAND_PXA3xx=y CONFIG_MTD_NAND_MARVELL=y
CONFIG_MTD_SPI_NOR=y CONFIG_MTD_SPI_NOR=y
CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_NBD=m
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/platform_data/mtd-nand-omap2.h> #include <linux/platform_data/mtd-nand-omap2.h>
#include <linux/platform_data/mtd-onenand-omap2.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -1138,6 +1137,112 @@ struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *reg, int cs) ...@@ -1138,6 +1137,112 @@ struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *reg, int cs)
} }
EXPORT_SYMBOL_GPL(gpmc_omap_get_nand_ops); EXPORT_SYMBOL_GPL(gpmc_omap_get_nand_ops);
static void gpmc_omap_onenand_calc_sync_timings(struct gpmc_timings *t,
struct gpmc_settings *s,
int freq, int latency)
{
struct gpmc_device_timings dev_t;
const int t_cer = 15;
const int t_avdp = 12;
const int t_cez = 20; /* max of t_cez, t_oez */
const int t_wpl = 40;
const int t_wph = 30;
int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
switch (freq) {
case 104:
min_gpmc_clk_period = 9600; /* 104 MHz */
t_ces = 3;
t_avds = 4;
t_avdh = 2;
t_ach = 3;
t_aavdh = 6;
t_rdyo = 6;
break;
case 83:
min_gpmc_clk_period = 12000; /* 83 MHz */
t_ces = 5;
t_avds = 4;
t_avdh = 2;
t_ach = 6;
t_aavdh = 6;
t_rdyo = 9;
break;
case 66:
min_gpmc_clk_period = 15000; /* 66 MHz */
t_ces = 6;
t_avds = 5;
t_avdh = 2;
t_ach = 6;
t_aavdh = 6;
t_rdyo = 11;
break;
default:
min_gpmc_clk_period = 18500; /* 54 MHz */
t_ces = 7;
t_avds = 7;
t_avdh = 7;
t_ach = 9;
t_aavdh = 7;
t_rdyo = 15;
break;
}
/* Set synchronous read timings */
memset(&dev_t, 0, sizeof(dev_t));
if (!s->sync_write) {
dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000;
dev_t.t_wpl = t_wpl * 1000;
dev_t.t_wph = t_wph * 1000;
dev_t.t_aavdh = t_aavdh * 1000;
}
dev_t.ce_xdelay = true;
dev_t.avd_xdelay = true;
dev_t.oe_xdelay = true;
dev_t.we_xdelay = true;
dev_t.clk = min_gpmc_clk_period;
dev_t.t_bacc = dev_t.clk;
dev_t.t_ces = t_ces * 1000;
dev_t.t_avds = t_avds * 1000;
dev_t.t_avdh = t_avdh * 1000;
dev_t.t_ach = t_ach * 1000;
dev_t.cyc_iaa = (latency + 1);
dev_t.t_cez_r = t_cez * 1000;
dev_t.t_cez_w = dev_t.t_cez_r;
dev_t.cyc_aavdh_oe = 1;
dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;
gpmc_calc_timings(t, s, &dev_t);
}
int gpmc_omap_onenand_set_timings(struct device *dev, int cs, int freq,
int latency,
struct gpmc_onenand_info *info)
{
int ret;
struct gpmc_timings gpmc_t;
struct gpmc_settings gpmc_s;
gpmc_read_settings_dt(dev->of_node, &gpmc_s);
info->sync_read = gpmc_s.sync_read;
info->sync_write = gpmc_s.sync_write;
info->burst_len = gpmc_s.burst_len;
if (!gpmc_s.sync_read && !gpmc_s.sync_write)
return 0;
gpmc_omap_onenand_calc_sync_timings(&gpmc_t, &gpmc_s, freq, latency);
ret = gpmc_cs_program_settings(cs, &gpmc_s);
if (ret < 0)
return ret;
return gpmc_cs_set_timings(cs, &gpmc_t, &gpmc_s);
}
EXPORT_SYMBOL_GPL(gpmc_omap_onenand_set_timings);
int gpmc_get_client_irq(unsigned irq_config) int gpmc_get_client_irq(unsigned irq_config)
{ {
if (!gpmc_irq_domain) { if (!gpmc_irq_domain) {
...@@ -1916,41 +2021,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np, ...@@ -1916,41 +2021,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
of_property_read_bool(np, "gpmc,time-para-granularity"); of_property_read_bool(np, "gpmc,time-para-granularity");
} }
#if IS_ENABLED(CONFIG_MTD_ONENAND)
static int gpmc_probe_onenand_child(struct platform_device *pdev,
struct device_node *child)
{
u32 val;
struct omap_onenand_platform_data *gpmc_onenand_data;
if (of_property_read_u32(child, "reg", &val) < 0) {
dev_err(&pdev->dev, "%pOF has no 'reg' property\n",
child);
return -ENODEV;
}
gpmc_onenand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_onenand_data),
GFP_KERNEL);
if (!gpmc_onenand_data)
return -ENOMEM;
gpmc_onenand_data->cs = val;
gpmc_onenand_data->of_node = child;
gpmc_onenand_data->dma_channel = -1;
if (!of_property_read_u32(child, "dma-channel", &val))
gpmc_onenand_data->dma_channel = val;
return gpmc_onenand_init(gpmc_onenand_data);
}
#else
static int gpmc_probe_onenand_child(struct platform_device *pdev,
struct device_node *child)
{
return 0;
}
#endif
/** /**
* gpmc_probe_generic_child - configures the gpmc for a child device * gpmc_probe_generic_child - configures the gpmc for a child device
* @pdev: pointer to gpmc platform device * @pdev: pointer to gpmc platform device
...@@ -2053,6 +2123,16 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, ...@@ -2053,6 +2123,16 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
} }
} }
if (of_node_cmp(child->name, "onenand") == 0) {
/* Warn about older DT blobs with no compatible property */
if (!of_property_read_bool(child, "compatible")) {
dev_warn(&pdev->dev,
"Incompatible OneNAND node: missing compatible");
ret = -EINVAL;
goto err;
}
}
if (of_device_is_compatible(child, "ti,omap2-nand")) { if (of_device_is_compatible(child, "ti,omap2-nand")) {
/* NAND specific setup */ /* NAND specific setup */
val = 8; val = 8;
...@@ -2077,8 +2157,9 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, ...@@ -2077,8 +2157,9 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
} else { } else {
ret = of_property_read_u32(child, "bank-width", ret = of_property_read_u32(child, "bank-width",
&gpmc_s.device_width); &gpmc_s.device_width);
if (ret < 0) { if (ret < 0 && !gpmc_s.device_width) {
dev_err(&pdev->dev, "%pOF has no 'bank-width' property\n", dev_err(&pdev->dev,
"%pOF has no 'gpmc,device-width' property\n",
child); child);
goto err; goto err;
} }
...@@ -2188,11 +2269,7 @@ static void gpmc_probe_dt_children(struct platform_device *pdev) ...@@ -2188,11 +2269,7 @@ static void gpmc_probe_dt_children(struct platform_device *pdev)
if (!child->name) if (!child->name)
continue; continue;
if (of_node_cmp(child->name, "onenand") == 0) ret = gpmc_probe_generic_child(pdev, child);
ret = gpmc_probe_onenand_child(pdev, child);
else
ret = gpmc_probe_generic_child(pdev, child);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to probe DT child '%s': %d\n", dev_err(&pdev->dev, "failed to probe DT child '%s': %d\n",
child->name, ret); child->name, ret);
......
...@@ -904,9 +904,6 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -904,9 +904,6 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
if (ooblen % DOC_LAYOUT_OOB_SIZE) if (ooblen % DOC_LAYOUT_OOB_SIZE)
return -EINVAL; return -EINVAL;
if (from + len > mtd->size)
return -EINVAL;
ops->oobretlen = 0; ops->oobretlen = 0;
ops->retlen = 0; ops->retlen = 0;
ret = 0; ret = 0;
...@@ -990,36 +987,6 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -990,36 +987,6 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
goto out; goto out;
} }
/**
* doc_read - Read bytes from flash
* @mtd: the device
* @from: the offset from first block and first page, in bytes, aligned on page
* size
* @len: the number of bytes to read (must be a multiple of 4)
* @retlen: the number of bytes actually read
* @buf: the filled in buffer
*
* Reads flash memory pages. This function does not read the OOB chunk, but only
* the page data.
*
* Returns 0 if read successful, of -EIO, -EINVAL if an error occurred
*/
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct mtd_oob_ops ops;
size_t ret;
memset(&ops, 0, sizeof(ops));
ops.datbuf = buf;
ops.len = len;
ops.mode = MTD_OPS_AUTO_OOB;
ret = doc_read_oob(mtd, from, &ops);
*retlen = ops.retlen;
return ret;
}
static int doc_reload_bbt(struct docg3 *docg3) static int doc_reload_bbt(struct docg3 *docg3)
{ {
int block = DOC_LAYOUT_BLOCK_BBT; int block = DOC_LAYOUT_BLOCK_BBT;
...@@ -1471,8 +1438,6 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, ...@@ -1471,8 +1438,6 @@ 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)
return -EINVAL;
ops->oobretlen = 0; ops->oobretlen = 0;
ops->retlen = 0; ops->retlen = 0;
...@@ -1513,39 +1478,6 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, ...@@ -1513,39 +1478,6 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
return ret; return ret;
} }
/**
* doc_write - Write a buffer to the chip
* @mtd: the device
* @to: the offset from first block and first page, in bytes, aligned on page
* size
* @len: the number of bytes to write (must be a full page size, ie. 512)
* @retlen: the number of bytes actually written (0 or 512)
* @buf: the buffer to get bytes from
*
* Writes data to the chip.
*
* Returns 0 if write successful, -EIO if write error
*/
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
struct docg3 *docg3 = mtd->priv;
int ret;
struct mtd_oob_ops ops;
doc_dbg("doc_write(to=%lld, len=%zu)\n", to, len);
ops.datbuf = (char *)buf;
ops.len = len;
ops.mode = MTD_OPS_PLACE_OOB;
ops.oobbuf = NULL;
ops.ooblen = 0;
ops.ooboffs = 0;
ret = doc_write_oob(mtd, to, &ops);
*retlen = ops.retlen;
return ret;
}
static struct docg3 *sysfs_dev2docg3(struct device *dev, static struct docg3 *sysfs_dev2docg3(struct device *dev,
struct device_attribute *attr) struct device_attribute *attr)
{ {
...@@ -1866,8 +1798,6 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) ...@@ -1866,8 +1798,6 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
mtd->writebufsize = 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->_erase = doc_erase; mtd->_erase = doc_erase;
mtd->_read = doc_read;
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;
......
...@@ -307,10 +307,18 @@ static int m25p_remove(struct spi_device *spi) ...@@ -307,10 +307,18 @@ static int m25p_remove(struct spi_device *spi)
{ {
struct m25p *flash = spi_get_drvdata(spi); struct m25p *flash = spi_get_drvdata(spi);
spi_nor_restore(&flash->spi_nor);
/* Clean up MTD stuff. */ /* Clean up MTD stuff. */
return mtd_device_unregister(&flash->spi_nor.mtd); return mtd_device_unregister(&flash->spi_nor.mtd);
} }
static void m25p_shutdown(struct spi_device *spi)
{
struct m25p *flash = spi_get_drvdata(spi);
spi_nor_restore(&flash->spi_nor);
}
/* /*
* Do NOT add to this array without reading the following: * Do NOT add to this array without reading the following:
* *
...@@ -386,6 +394,7 @@ static struct spi_driver m25p80_driver = { ...@@ -386,6 +394,7 @@ static struct spi_driver m25p80_driver = {
.id_table = m25p_ids, .id_table = m25p_ids,
.probe = m25p_probe, .probe = m25p_probe,
.remove = m25p_remove, .remove = m25p_remove,
.shutdown = m25p_shutdown,
/* REVISIT: many of these chips have deep power-down modes, which /* REVISIT: many of these chips have deep power-down modes, which
* should clearly be entered on suspend() to minimize power use. * should clearly be entered on suspend() to minimize power use.
......
...@@ -68,6 +68,7 @@ static int mchp23k256_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -68,6 +68,7 @@ static int mchp23k256_write(struct mtd_info *mtd, loff_t to, size_t len,
struct spi_transfer transfer[2] = {}; struct spi_transfer transfer[2] = {};
struct spi_message message; struct spi_message message;
unsigned char command[MAX_CMD_SIZE]; unsigned char command[MAX_CMD_SIZE];
int ret;
spi_message_init(&message); spi_message_init(&message);
...@@ -84,12 +85,16 @@ static int mchp23k256_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -84,12 +85,16 @@ static int mchp23k256_write(struct mtd_info *mtd, loff_t to, size_t len,
mutex_lock(&flash->lock); mutex_lock(&flash->lock);
spi_sync(flash->spi, &message); ret = spi_sync(flash->spi, &message);
mutex_unlock(&flash->lock);
if (ret)
return ret;
if (retlen && message.actual_length > sizeof(command)) if (retlen && message.actual_length > sizeof(command))
*retlen += message.actual_length - sizeof(command); *retlen += message.actual_length - sizeof(command);
mutex_unlock(&flash->lock);
return 0; return 0;
} }
...@@ -100,6 +105,7 @@ static int mchp23k256_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -100,6 +105,7 @@ static int mchp23k256_read(struct mtd_info *mtd, loff_t from, size_t len,
struct spi_transfer transfer[2] = {}; struct spi_transfer transfer[2] = {};
struct spi_message message; struct spi_message message;
unsigned char command[MAX_CMD_SIZE]; unsigned char command[MAX_CMD_SIZE];
int ret;
spi_message_init(&message); spi_message_init(&message);
...@@ -117,12 +123,16 @@ static int mchp23k256_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -117,12 +123,16 @@ static int mchp23k256_read(struct mtd_info *mtd, loff_t from, size_t len,
mutex_lock(&flash->lock); mutex_lock(&flash->lock);
spi_sync(flash->spi, &message); ret = spi_sync(flash->spi, &message);
mutex_unlock(&flash->lock);
if (ret)
return ret;
if (retlen && message.actual_length > sizeof(command)) if (retlen && message.actual_length > sizeof(command))
*retlen += message.actual_length - sizeof(command); *retlen += message.actual_length - sizeof(command);
mutex_unlock(&flash->lock);
return 0; return 0;
} }
......
...@@ -503,6 +503,11 @@ int add_mtd_device(struct mtd_info *mtd) ...@@ -503,6 +503,11 @@ int add_mtd_device(struct mtd_info *mtd)
return -EEXIST; return -EEXIST;
BUG_ON(mtd->writesize == 0); BUG_ON(mtd->writesize == 0);
if (WARN_ON((!mtd->erasesize || !mtd->_erase) &&
!(mtd->flags & MTD_NO_ERASE)))
return -EINVAL;
mutex_lock(&mtd_table_mutex); mutex_lock(&mtd_table_mutex);
i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL); i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
...@@ -1053,7 +1058,20 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, ...@@ -1053,7 +1058,20 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
* representing the maximum number of bitflips that were corrected on * representing the maximum number of bitflips that were corrected on
* any one ecc region (if applicable; zero otherwise). * any one ecc region (if applicable; zero otherwise).
*/ */
ret_code = mtd->_read(mtd, from, len, retlen, buf); if (mtd->_read) {
ret_code = mtd->_read(mtd, from, len, retlen, buf);
} else if (mtd->_read_oob) {
struct mtd_oob_ops ops = {
.len = len,
.datbuf = buf,
};
ret_code = mtd->_read_oob(mtd, from, &ops);
*retlen = ops.retlen;
} else {
return -ENOTSUPP;
}
if (unlikely(ret_code < 0)) if (unlikely(ret_code < 0))
return ret_code; return ret_code;
if (mtd->ecc_strength == 0) if (mtd->ecc_strength == 0)
...@@ -1068,11 +1086,25 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, ...@@ -1068,11 +1086,25 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
*retlen = 0; *retlen = 0;
if (to < 0 || to >= mtd->size || len > mtd->size - to) if (to < 0 || to >= mtd->size || len > mtd->size - to)
return -EINVAL; return -EINVAL;
if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE)) if ((!mtd->_write && !mtd->_write_oob) ||
!(mtd->flags & MTD_WRITEABLE))
return -EROFS; return -EROFS;
if (!len) if (!len)
return 0; return 0;
ledtrig_mtd_activity(); ledtrig_mtd_activity();
if (!mtd->_write) {
struct mtd_oob_ops ops = {
.len = len,
.datbuf = (u8 *)buf,
};
int ret;
ret = mtd->_write_oob(mtd, to, &ops);
*retlen = ops.retlen;
return ret;
}
return mtd->_write(mtd, to, len, retlen, buf); return mtd->_write(mtd, to, len, retlen, buf);
} }
EXPORT_SYMBOL_GPL(mtd_write); EXPORT_SYMBOL_GPL(mtd_write);
......
...@@ -105,34 +105,17 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -105,34 +105,17 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops) struct mtd_oob_ops *ops)
{ {
struct mtd_part *part = mtd_to_part(mtd); struct mtd_part *part = mtd_to_part(mtd);
struct mtd_ecc_stats stats;
int res; int res;
if (from >= mtd->size) stats = part->parent->ecc_stats;
return -EINVAL;
if (ops->datbuf && from + ops->len > mtd->size)
return -EINVAL;
/*
* If OOB is also requested, make sure that we do not read past the end
* of this partition.
*/
if (ops->oobbuf) {
size_t len, pages;
len = mtd_oobavail(mtd, ops);
pages = mtd_div_by_ws(mtd->size, mtd);
pages -= mtd_div_by_ws(from, mtd);
if (ops->ooboffs + ops->ooblen > pages * len)
return -EINVAL;
}
res = part->parent->_read_oob(part->parent, from + part->offset, ops); res = part->parent->_read_oob(part->parent, from + part->offset, ops);
if (unlikely(res)) { if (unlikely(mtd_is_eccerr(res)))
if (mtd_is_bitflip(res)) mtd->ecc_stats.failed +=
mtd->ecc_stats.corrected++; part->parent->ecc_stats.failed - stats.failed;
if (mtd_is_eccerr(res)) else
mtd->ecc_stats.failed++; mtd->ecc_stats.corrected +=
} part->parent->ecc_stats.corrected - stats.corrected;
return res; return res;
} }
...@@ -189,10 +172,6 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to, ...@@ -189,10 +172,6 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to,
{ {
struct mtd_part *part = mtd_to_part(mtd); struct mtd_part *part = mtd_to_part(mtd);
if (to >= mtd->size)
return -EINVAL;
if (ops->datbuf && to + ops->len > mtd->size)
return -EINVAL;
return part->parent->_write_oob(part->parent, to + part->offset, ops); return part->parent->_write_oob(part->parent, to + part->offset, ops);
} }
...@@ -435,8 +414,10 @@ static struct mtd_part *allocate_partition(struct mtd_info *parent, ...@@ -435,8 +414,10 @@ static struct mtd_part *allocate_partition(struct mtd_info *parent,
parent->dev.parent; parent->dev.parent;
slave->mtd.dev.of_node = part->of_node; slave->mtd.dev.of_node = part->of_node;
slave->mtd._read = part_read; if (parent->_read)
slave->mtd._write = part_write; slave->mtd._read = part_read;
if (parent->_write)
slave->mtd._write = part_write;
if (parent->_panic_write) if (parent->_panic_write)
slave->mtd._panic_write = part_panic_write; slave->mtd._panic_write = part_panic_write;
......
...@@ -1223,8 +1223,9 @@ static int mtdswap_show(struct seq_file *s, void *data) ...@@ -1223,8 +1223,9 @@ static int mtdswap_show(struct seq_file *s, void *data)
unsigned int max[MTDSWAP_TREE_CNT]; unsigned int max[MTDSWAP_TREE_CNT];
unsigned int i, cw = 0, cwp = 0, cwecount = 0, bb_cnt, mapped, pages; unsigned int i, cw = 0, cwp = 0, cwecount = 0, bb_cnt, mapped, pages;
uint64_t use_size; uint64_t use_size;
char *name[] = {"clean", "used", "low", "high", "dirty", "bitflip", static const char * const name[] = {
"failing"}; "clean", "used", "low", "high", "dirty", "bitflip", "failing"
};
mutex_lock(&d->mbd_dev->lock); mutex_lock(&d->mbd_dev->lock);
......
...@@ -315,6 +315,7 @@ config MTD_NAND_ATMEL ...@@ -315,6 +315,7 @@ config MTD_NAND_ATMEL
config MTD_NAND_PXA3xx config MTD_NAND_PXA3xx
tristate "NAND support on PXA3xx and Armada 370/XP" tristate "NAND support on PXA3xx and Armada 370/XP"
depends on !MTD_NAND_MARVELL
depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU
help help
...@@ -323,6 +324,18 @@ config MTD_NAND_PXA3xx ...@@ -323,6 +324,18 @@ config MTD_NAND_PXA3xx
platforms (XP, 370, 375, 38x, 39x) and 64-bit Armada platforms (XP, 370, 375, 38x, 39x) and 64-bit Armada
platforms (7K, 8K) (NFCv2). platforms (7K, 8K) (NFCv2).
config MTD_NAND_MARVELL
tristate "NAND controller support on Marvell boards"
depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \
COMPILE_TEST
depends on HAS_IOMEM
help
This enables the NAND flash controller driver for Marvell boards,
including:
- PXA3xx processors (NFCv1)
- 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2)
- 64-bit Aramda platforms (7k, 8k) (NFCv2)
config MTD_NAND_SLC_LPC32XX config MTD_NAND_SLC_LPC32XX
tristate "NXP LPC32xx SLC Controller" tristate "NXP LPC32xx SLC Controller"
depends on ARCH_LPC32XX depends on ARCH_LPC32XX
...@@ -376,9 +389,7 @@ config MTD_NAND_GPMI_NAND ...@@ -376,9 +389,7 @@ config MTD_NAND_GPMI_NAND
Enables NAND Flash support for IMX23, IMX28 or IMX6. Enables NAND Flash support for IMX23, IMX28 or IMX6.
The GPMI controller is very powerful, with the help of BCH The GPMI controller is very powerful, with the help of BCH
module, it can do the hardware ECC. The GPMI supports several module, it can do the hardware ECC. The GPMI supports several
NAND flashs at the same time. The GPMI may conflicts with other NAND flashs at the same time.
block, such as SD card. So pay attention to it when you enable
the GPMI.
config MTD_NAND_BRCMNAND config MTD_NAND_BRCMNAND
tristate "Broadcom STB NAND controller" tristate "Broadcom STB NAND controller"
......
...@@ -32,6 +32,7 @@ obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o ...@@ -32,6 +32,7 @@ obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o
obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o
obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
......
...@@ -841,6 +841,8 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf, ...@@ -841,6 +841,8 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_nand *nand = to_atmel_nand(chip);
int ret; int ret;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw); ret = atmel_nand_pmecc_enable(chip, NAND_ECC_WRITE, raw);
if (ret) if (ret)
return ret; return ret;
...@@ -857,7 +859,7 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf, ...@@ -857,7 +859,7 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0; return nand_prog_page_end_op(chip);
} }
static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
...@@ -881,6 +883,8 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf, ...@@ -881,6 +883,8 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
int ret; int ret;
nand_read_page_op(chip, page, 0, NULL, 0);
ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw); ret = atmel_nand_pmecc_enable(chip, NAND_ECC_READ, raw);
if (ret) if (ret)
return ret; return ret;
...@@ -1000,7 +1004,7 @@ static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf, ...@@ -1000,7 +1004,7 @@ static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
* to the non-optimized one. * to the non-optimized one.
*/ */
if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) { if (nand->activecs->rb.type != ATMEL_NAND_NATIVE_RB) {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); nand_read_page_op(chip, page, 0, NULL, 0);
return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page,
raw); raw);
...@@ -1178,7 +1182,6 @@ static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand) ...@@ -1178,7 +1182,6 @@ static int atmel_hsmc_nand_ecc_init(struct atmel_nand *nand)
chip->ecc.write_page = atmel_hsmc_nand_pmecc_write_page; chip->ecc.write_page = atmel_hsmc_nand_pmecc_write_page;
chip->ecc.read_page_raw = atmel_hsmc_nand_pmecc_read_page_raw; chip->ecc.read_page_raw = atmel_hsmc_nand_pmecc_read_page_raw;
chip->ecc.write_page_raw = atmel_hsmc_nand_pmecc_write_page_raw; chip->ecc.write_page_raw = atmel_hsmc_nand_pmecc_write_page_raw;
chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
return 0; return 0;
} }
......
...@@ -572,6 +572,8 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, ...@@ -572,6 +572,8 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page) uint8_t *buf, int oob_required, int page)
{ {
nand_read_page_op(chip, page, 0, NULL, 0);
bf5xx_nand_read_buf(mtd, buf, mtd->writesize); bf5xx_nand_read_buf(mtd, buf, mtd->writesize);
bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize); bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
...@@ -582,10 +584,10 @@ static int bf5xx_nand_write_page_raw(struct mtd_info *mtd, ...@@ -582,10 +584,10 @@ static int bf5xx_nand_write_page_raw(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf, int oob_required, struct nand_chip *chip, const uint8_t *buf, int oob_required,
int page) int page)
{ {
bf5xx_nand_write_buf(mtd, buf, mtd->writesize); nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0; return nand_prog_page_end_op(chip);
} }
/* /*
......
...@@ -1071,7 +1071,7 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp) ...@@ -1071,7 +1071,7 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp)
return; return;
brcmnand_set_wp(ctrl, wp); brcmnand_set_wp(ctrl, wp);
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); nand_status_op(chip, NULL);
/* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */ /* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */
ret = bcmnand_ctrl_poll_status(ctrl, ret = bcmnand_ctrl_poll_status(ctrl,
NAND_CTRL_RDY | NAND_CTRL_RDY |
...@@ -1453,7 +1453,7 @@ static uint8_t brcmnand_read_byte(struct mtd_info *mtd) ...@@ -1453,7 +1453,7 @@ static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
/* At FC_BYTES boundary, switch to next column */ /* At FC_BYTES boundary, switch to next column */
if (host->last_byte > 0 && offs == 0) if (host->last_byte > 0 && offs == 0)
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, addr, -1); nand_change_read_column_op(chip, addr, NULL, 0, false);
ret = ctrl->flash_cache[offs]; ret = ctrl->flash_cache[offs];
break; break;
...@@ -1681,7 +1681,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd, ...@@ -1681,7 +1681,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
int ret; int ret;
if (!buf) { if (!buf) {
buf = chip->buffers->databuf; buf = chip->data_buf;
/* Invalidate page cache */ /* Invalidate page cache */
chip->pagebuf = -1; chip->pagebuf = -1;
} }
...@@ -1689,7 +1689,6 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd, ...@@ -1689,7 +1689,6 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
sas = mtd->oobsize / chip->ecc.steps; sas = mtd->oobsize / chip->ecc.steps;
/* read without ecc for verification */ /* read without ecc for verification */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page); ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
if (ret) if (ret)
return ret; return ret;
...@@ -1793,6 +1792,8 @@ static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1793,6 +1792,8 @@ static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
struct brcmnand_host *host = nand_get_controller_data(chip); struct brcmnand_host *host = nand_get_controller_data(chip);
u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL; u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
nand_read_page_op(chip, page, 0, NULL, 0);
return brcmnand_read(mtd, chip, host->last_addr, return brcmnand_read(mtd, chip, host->last_addr,
mtd->writesize >> FC_SHIFT, (u32 *)buf, oob); mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
} }
...@@ -1804,6 +1805,8 @@ static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1804,6 +1805,8 @@ static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL; u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
int ret; int ret;
nand_read_page_op(chip, page, 0, NULL, 0);
brcmnand_set_ecc_enabled(host, 0); brcmnand_set_ecc_enabled(host, 0);
ret = brcmnand_read(mtd, chip, host->last_addr, ret = brcmnand_read(mtd, chip, host->last_addr,
mtd->writesize >> FC_SHIFT, (u32 *)buf, oob); mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
...@@ -1909,8 +1912,10 @@ static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1909,8 +1912,10 @@ static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
struct brcmnand_host *host = nand_get_controller_data(chip); struct brcmnand_host *host = nand_get_controller_data(chip);
void *oob = oob_required ? chip->oob_poi : NULL; void *oob = oob_required ? chip->oob_poi : NULL;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob); brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
return 0;
return nand_prog_page_end_op(chip);
} }
static int brcmnand_write_page_raw(struct mtd_info *mtd, static int brcmnand_write_page_raw(struct mtd_info *mtd,
...@@ -1920,10 +1925,12 @@ static int brcmnand_write_page_raw(struct mtd_info *mtd, ...@@ -1920,10 +1925,12 @@ static int brcmnand_write_page_raw(struct mtd_info *mtd,
struct brcmnand_host *host = nand_get_controller_data(chip); struct brcmnand_host *host = nand_get_controller_data(chip);
void *oob = oob_required ? chip->oob_poi : NULL; void *oob = oob_required ? chip->oob_poi : NULL;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
brcmnand_set_ecc_enabled(host, 0); brcmnand_set_ecc_enabled(host, 0);
brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob); brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
brcmnand_set_ecc_enabled(host, 1); brcmnand_set_ecc_enabled(host, 1);
return 0;
return nand_prog_page_end_op(chip);
} }
static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
...@@ -2193,16 +2200,9 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) ...@@ -2193,16 +2200,9 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
if (ctrl->nand_version >= 0x0702) if (ctrl->nand_version >= 0x0702)
tmp |= ACC_CONTROL_RD_ERASED; tmp |= ACC_CONTROL_RD_ERASED;
tmp &= ~ACC_CONTROL_FAST_PGM_RDIN; tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
if (ctrl->features & BRCMNAND_HAS_PREFETCH) { if (ctrl->features & BRCMNAND_HAS_PREFETCH)
/* tmp &= ~ACC_CONTROL_PREFETCH;
* FIXME: Flash DMA + prefetch may see spurious erased-page ECC
* errors
*/
if (has_flash_dma(ctrl))
tmp &= ~ACC_CONTROL_PREFETCH;
else
tmp |= ACC_CONTROL_PREFETCH;
}
nand_writereg(ctrl, offs, tmp); nand_writereg(ctrl, offs, tmp);
return 0; return 0;
...@@ -2230,6 +2230,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn) ...@@ -2230,6 +2230,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
nand_set_controller_data(chip, host); nand_set_controller_data(chip, host);
mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d", mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d",
host->cs); host->cs);
if (!mtd->name)
return -ENOMEM;
mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE;
mtd->dev.parent = &pdev->dev; mtd->dev.parent = &pdev->dev;
...@@ -2369,12 +2372,11 @@ static int brcmnand_resume(struct device *dev) ...@@ -2369,12 +2372,11 @@ static int brcmnand_resume(struct device *dev)
list_for_each_entry(host, &ctrl->host_list, node) { list_for_each_entry(host, &ctrl->host_list, node) {
struct nand_chip *chip = &host->chip; struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
brcmnand_save_restore_cs_config(host, 1); brcmnand_save_restore_cs_config(host, 1);
/* Reset the chip, required by some chips after power-up */ /* Reset the chip, required by some chips after power-up */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset_op(chip);
} }
return 0; return 0;
......
...@@ -353,23 +353,15 @@ static void cafe_nand_bug(struct mtd_info *mtd) ...@@ -353,23 +353,15 @@ static void cafe_nand_bug(struct mtd_info *mtd)
static int cafe_nand_write_oob(struct mtd_info *mtd, static int cafe_nand_write_oob(struct mtd_info *mtd,
struct nand_chip *chip, int page) struct nand_chip *chip, int page)
{ {
int status = 0; return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
mtd->oobsize);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
/* Don't use -- use nand_read_oob_std for now */ /* Don't use -- use nand_read_oob_std for now */
static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
} }
/** /**
* cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read
...@@ -391,7 +383,7 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -391,7 +383,7 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
cafe_readl(cafe, NAND_ECC_RESULT), cafe_readl(cafe, NAND_ECC_RESULT),
cafe_readl(cafe, NAND_ECC_SYN01)); cafe_readl(cafe, NAND_ECC_SYN01));
chip->read_buf(mtd, buf, mtd->writesize); nand_read_page_op(chip, page, 0, buf, mtd->writesize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) { if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
...@@ -549,13 +541,13 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd, ...@@ -549,13 +541,13 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
{ {
struct cafe_priv *cafe = nand_get_controller_data(chip); struct cafe_priv *cafe = nand_get_controller_data(chip);
chip->write_buf(mtd, buf, mtd->writesize); nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
/* Set up ECC autogeneration */ /* Set up ECC autogeneration */
cafe->ctl2 |= (1<<30); cafe->ctl2 |= (1<<30);
return 0; return nand_prog_page_end_op(chip);
} }
static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs) static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
...@@ -613,7 +605,6 @@ static int cafe_nand_probe(struct pci_dev *pdev, ...@@ -613,7 +605,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
uint32_t ctrl; uint32_t ctrl;
int err = 0; int err = 0;
int old_dma; int old_dma;
struct nand_buffers *nbuf;
/* Very old versions shared the same PCI ident for all three /* Very old versions shared the same PCI ident for all three
functions on the chip. Verify the class too... */ functions on the chip. Verify the class too... */
...@@ -661,7 +652,6 @@ static int cafe_nand_probe(struct pci_dev *pdev, ...@@ -661,7 +652,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
/* Enable the following for a flash based bad block table */ /* Enable the following for a flash based bad block table */
cafe->nand.bbt_options = NAND_BBT_USE_FLASH; cafe->nand.bbt_options = NAND_BBT_USE_FLASH;
cafe->nand.options = NAND_OWN_BUFFERS;
if (skipbbt) { if (skipbbt) {
cafe->nand.options |= NAND_SKIP_BBTSCAN; cafe->nand.options |= NAND_SKIP_BBTSCAN;
...@@ -731,32 +721,20 @@ static int cafe_nand_probe(struct pci_dev *pdev, ...@@ -731,32 +721,20 @@ static int cafe_nand_probe(struct pci_dev *pdev,
if (err) if (err)
goto out_irq; goto out_irq;
cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112,
2112 + sizeof(struct nand_buffers) + &cafe->dmaaddr, GFP_KERNEL);
mtd->writesize + mtd->oobsize,
&cafe->dmaaddr, GFP_KERNEL);
if (!cafe->dmabuf) { if (!cafe->dmabuf) {
err = -ENOMEM; err = -ENOMEM;
goto out_irq; goto out_irq;
} }
cafe->nand.buffers = nbuf = (void *)cafe->dmabuf + 2112;
/* Set up DMA address */ /* Set up DMA address */
cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0); cafe_writel(cafe, lower_32_bits(cafe->dmaaddr), NAND_DMA_ADDR0);
if (sizeof(cafe->dmaaddr) > 4) cafe_writel(cafe, upper_32_bits(cafe->dmaaddr), NAND_DMA_ADDR1);
/* Shift in two parts to shut the compiler up */
cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
else
cafe_writel(cafe, 0, NAND_DMA_ADDR1);
cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n", cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf); cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
/* this driver does not need the @ecccalc and @ecccode */
nbuf->ecccalc = NULL;
nbuf->ecccode = NULL;
nbuf->databuf = (uint8_t *)(nbuf + 1);
/* Restore the DMA flag */ /* Restore the DMA flag */
usedma = old_dma; usedma = old_dma;
...@@ -801,10 +779,7 @@ static int cafe_nand_probe(struct pci_dev *pdev, ...@@ -801,10 +779,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
goto out; goto out;
out_free_dma: out_free_dma:
dma_free_coherent(&cafe->pdev->dev, dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
2112 + sizeof(struct nand_buffers) +
mtd->writesize + mtd->oobsize,
cafe->dmabuf, cafe->dmaaddr);
out_irq: out_irq:
/* Disable NAND IRQ in global IRQ mask register */ /* Disable NAND IRQ in global IRQ mask register */
cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK); cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
...@@ -829,10 +804,7 @@ static void cafe_nand_remove(struct pci_dev *pdev) ...@@ -829,10 +804,7 @@ static void cafe_nand_remove(struct pci_dev *pdev)
nand_release(mtd); nand_release(mtd);
free_rs(cafe->rs); free_rs(cafe->rs);
pci_iounmap(pdev, cafe->mmio); pci_iounmap(pdev, cafe->mmio);
dma_free_coherent(&cafe->pdev->dev, dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
2112 + sizeof(struct nand_buffers) +
mtd->writesize + mtd->oobsize,
cafe->dmabuf, cafe->dmaaddr);
kfree(cafe); kfree(cafe);
} }
......
...@@ -330,16 +330,12 @@ static int denali_check_erased_page(struct mtd_info *mtd, ...@@ -330,16 +330,12 @@ static int denali_check_erased_page(struct mtd_info *mtd,
unsigned long uncor_ecc_flags, unsigned long uncor_ecc_flags,
unsigned int max_bitflips) unsigned int max_bitflips)
{ {
uint8_t *ecc_code = chip->buffers->ecccode; struct denali_nand_info *denali = mtd_to_denali(mtd);
uint8_t *ecc_code = chip->oob_poi + denali->oob_skip_bytes;
int ecc_steps = chip->ecc.steps; int ecc_steps = chip->ecc.steps;
int ecc_size = chip->ecc.size; int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes; int ecc_bytes = chip->ecc.bytes;
int i, ret, stat; int i, stat;
ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
chip->ecc.total);
if (ret)
return ret;
for (i = 0; i < ecc_steps; i++) { for (i = 0; i < ecc_steps; i++) {
if (!(uncor_ecc_flags & BIT(i))) if (!(uncor_ecc_flags & BIT(i)))
...@@ -645,8 +641,6 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -645,8 +641,6 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
int page, int write) int page, int write)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
unsigned int start_cmd = write ? NAND_CMD_SEQIN : NAND_CMD_READ0;
unsigned int rnd_cmd = write ? NAND_CMD_RNDIN : NAND_CMD_RNDOUT;
int writesize = mtd->writesize; int writesize = mtd->writesize;
int oobsize = mtd->oobsize; int oobsize = mtd->oobsize;
uint8_t *bufpoi = chip->oob_poi; uint8_t *bufpoi = chip->oob_poi;
...@@ -658,11 +652,11 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -658,11 +652,11 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
int i, pos, len; int i, pos, len;
/* BBM at the beginning of the OOB area */ /* BBM at the beginning of the OOB area */
chip->cmdfunc(mtd, start_cmd, writesize, page);
if (write) if (write)
chip->write_buf(mtd, bufpoi, oob_skip); nand_prog_page_begin_op(chip, page, writesize, bufpoi,
oob_skip);
else else
chip->read_buf(mtd, bufpoi, oob_skip); nand_read_page_op(chip, page, writesize, bufpoi, oob_skip);
bufpoi += oob_skip; bufpoi += oob_skip;
/* OOB ECC */ /* OOB ECC */
...@@ -675,30 +669,35 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -675,30 +669,35 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
else if (pos + len > writesize) else if (pos + len > writesize)
len = writesize - pos; len = writesize - pos;
chip->cmdfunc(mtd, rnd_cmd, pos, -1);
if (write) if (write)
chip->write_buf(mtd, bufpoi, len); nand_change_write_column_op(chip, pos, bufpoi, len,
false);
else else
chip->read_buf(mtd, bufpoi, len); nand_change_read_column_op(chip, pos, bufpoi, len,
false);
bufpoi += len; bufpoi += len;
if (len < ecc_bytes) { if (len < ecc_bytes) {
len = ecc_bytes - len; len = ecc_bytes - len;
chip->cmdfunc(mtd, rnd_cmd, writesize + oob_skip, -1);
if (write) if (write)
chip->write_buf(mtd, bufpoi, len); nand_change_write_column_op(chip, writesize +
oob_skip, bufpoi,
len, false);
else else
chip->read_buf(mtd, bufpoi, len); nand_change_read_column_op(chip, writesize +
oob_skip, bufpoi,
len, false);
bufpoi += len; bufpoi += len;
} }
} }
/* OOB free */ /* OOB free */
len = oobsize - (bufpoi - chip->oob_poi); len = oobsize - (bufpoi - chip->oob_poi);
chip->cmdfunc(mtd, rnd_cmd, size - len, -1);
if (write) if (write)
chip->write_buf(mtd, bufpoi, len); nand_change_write_column_op(chip, size - len, bufpoi, len,
false);
else else
chip->read_buf(mtd, bufpoi, len); nand_change_read_column_op(chip, size - len, bufpoi, len,
false);
} }
static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
...@@ -710,12 +709,12 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -710,12 +709,12 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
int ecc_steps = chip->ecc.steps; int ecc_steps = chip->ecc.steps;
int ecc_size = chip->ecc.size; int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes; int ecc_bytes = chip->ecc.bytes;
void *dma_buf = denali->buf; void *tmp_buf = denali->buf;
int oob_skip = denali->oob_skip_bytes; int oob_skip = denali->oob_skip_bytes;
size_t size = writesize + oobsize; size_t size = writesize + oobsize;
int ret, i, pos, len; int ret, i, pos, len;
ret = denali_data_xfer(denali, dma_buf, size, page, 1, 0); ret = denali_data_xfer(denali, tmp_buf, size, page, 1, 0);
if (ret) if (ret)
return ret; return ret;
...@@ -730,11 +729,11 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -730,11 +729,11 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
else if (pos + len > writesize) else if (pos + len > writesize)
len = writesize - pos; len = writesize - pos;
memcpy(buf, dma_buf + pos, len); memcpy(buf, tmp_buf + pos, len);
buf += len; buf += len;
if (len < ecc_size) { if (len < ecc_size) {
len = ecc_size - len; len = ecc_size - len;
memcpy(buf, dma_buf + writesize + oob_skip, memcpy(buf, tmp_buf + writesize + oob_skip,
len); len);
buf += len; buf += len;
} }
...@@ -745,7 +744,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -745,7 +744,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *oob = chip->oob_poi; uint8_t *oob = chip->oob_poi;
/* BBM at the beginning of the OOB area */ /* BBM at the beginning of the OOB area */
memcpy(oob, dma_buf + writesize, oob_skip); memcpy(oob, tmp_buf + writesize, oob_skip);
oob += oob_skip; oob += oob_skip;
/* OOB ECC */ /* OOB ECC */
...@@ -758,11 +757,11 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -758,11 +757,11 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
else if (pos + len > writesize) else if (pos + len > writesize)
len = writesize - pos; len = writesize - pos;
memcpy(oob, dma_buf + pos, len); memcpy(oob, tmp_buf + pos, len);
oob += len; oob += len;
if (len < ecc_bytes) { if (len < ecc_bytes) {
len = ecc_bytes - len; len = ecc_bytes - len;
memcpy(oob, dma_buf + writesize + oob_skip, memcpy(oob, tmp_buf + writesize + oob_skip,
len); len);
oob += len; oob += len;
} }
...@@ -770,7 +769,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -770,7 +769,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
/* OOB free */ /* OOB free */
len = oobsize - (oob - chip->oob_poi); len = oobsize - (oob - chip->oob_poi);
memcpy(oob, dma_buf + size - len, len); memcpy(oob, tmp_buf + size - len, len);
} }
return 0; return 0;
...@@ -788,16 +787,12 @@ static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -788,16 +787,12 @@ static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
struct denali_nand_info *denali = mtd_to_denali(mtd); struct denali_nand_info *denali = mtd_to_denali(mtd);
int status;
denali_reset_irq(denali); denali_reset_irq(denali);
denali_oob_xfer(mtd, chip, page, 1); denali_oob_xfer(mtd, chip, page, 1);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
...@@ -841,7 +836,7 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -841,7 +836,7 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
int ecc_steps = chip->ecc.steps; int ecc_steps = chip->ecc.steps;
int ecc_size = chip->ecc.size; int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes; int ecc_bytes = chip->ecc.bytes;
void *dma_buf = denali->buf; void *tmp_buf = denali->buf;
int oob_skip = denali->oob_skip_bytes; int oob_skip = denali->oob_skip_bytes;
size_t size = writesize + oobsize; size_t size = writesize + oobsize;
int i, pos, len; int i, pos, len;
...@@ -851,7 +846,7 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -851,7 +846,7 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
* This simplifies the logic. * This simplifies the logic.
*/ */
if (!buf || !oob_required) if (!buf || !oob_required)
memset(dma_buf, 0xff, size); memset(tmp_buf, 0xff, size);
/* Arrange the buffer for syndrome payload/ecc layout */ /* Arrange the buffer for syndrome payload/ecc layout */
if (buf) { if (buf) {
...@@ -864,11 +859,11 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -864,11 +859,11 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
else if (pos + len > writesize) else if (pos + len > writesize)
len = writesize - pos; len = writesize - pos;
memcpy(dma_buf + pos, buf, len); memcpy(tmp_buf + pos, buf, len);
buf += len; buf += len;
if (len < ecc_size) { if (len < ecc_size) {
len = ecc_size - len; len = ecc_size - len;
memcpy(dma_buf + writesize + oob_skip, buf, memcpy(tmp_buf + writesize + oob_skip, buf,
len); len);
buf += len; buf += len;
} }
...@@ -879,7 +874,7 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -879,7 +874,7 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *oob = chip->oob_poi; const uint8_t *oob = chip->oob_poi;
/* BBM at the beginning of the OOB area */ /* BBM at the beginning of the OOB area */
memcpy(dma_buf + writesize, oob, oob_skip); memcpy(tmp_buf + writesize, oob, oob_skip);
oob += oob_skip; oob += oob_skip;
/* OOB ECC */ /* OOB ECC */
...@@ -892,11 +887,11 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -892,11 +887,11 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
else if (pos + len > writesize) else if (pos + len > writesize)
len = writesize - pos; len = writesize - pos;
memcpy(dma_buf + pos, oob, len); memcpy(tmp_buf + pos, oob, len);
oob += len; oob += len;
if (len < ecc_bytes) { if (len < ecc_bytes) {
len = ecc_bytes - len; len = ecc_bytes - len;
memcpy(dma_buf + writesize + oob_skip, oob, memcpy(tmp_buf + writesize + oob_skip, oob,
len); len);
oob += len; oob += len;
} }
...@@ -904,10 +899,10 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -904,10 +899,10 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
/* OOB free */ /* OOB free */
len = oobsize - (oob - chip->oob_poi); len = oobsize - (oob - chip->oob_poi);
memcpy(dma_buf + size - len, oob, len); memcpy(tmp_buf + size - len, oob, len);
} }
return denali_data_xfer(denali, dma_buf, size, page, 1, 1); return denali_data_xfer(denali, tmp_buf, size, page, 1, 1);
} }
static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
...@@ -951,7 +946,7 @@ static int denali_erase(struct mtd_info *mtd, int page) ...@@ -951,7 +946,7 @@ static int denali_erase(struct mtd_info *mtd, int page)
irq_status = denali_wait_for_irq(denali, irq_status = denali_wait_for_irq(denali,
INTR__ERASE_COMP | INTR__ERASE_FAIL); INTR__ERASE_COMP | INTR__ERASE_FAIL);
return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL; return irq_status & INTR__ERASE_COMP ? 0 : -EIO;
} }
static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
...@@ -1359,7 +1354,6 @@ int denali_init(struct denali_nand_info *denali) ...@@ -1359,7 +1354,6 @@ int denali_init(struct denali_nand_info *denali)
chip->read_buf = denali_read_buf; chip->read_buf = denali_read_buf;
chip->write_buf = denali_write_buf; chip->write_buf = denali_write_buf;
} }
chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
chip->ecc.read_page = denali_read_page; chip->ecc.read_page = denali_read_page;
chip->ecc.read_page_raw = denali_read_page_raw; chip->ecc.read_page_raw = denali_read_page_raw;
chip->ecc.write_page = denali_write_page; chip->ecc.write_page = denali_write_page;
......
...@@ -329,7 +329,7 @@ struct denali_nand_info { ...@@ -329,7 +329,7 @@ struct denali_nand_info {
#define DENALI_CAP_DMA_64BIT BIT(1) #define DENALI_CAP_DMA_64BIT BIT(1)
int denali_calc_ecc_bytes(int step_size, int strength); int denali_calc_ecc_bytes(int step_size, int strength);
extern int denali_init(struct denali_nand_info *denali); int denali_init(struct denali_nand_info *denali);
extern void denali_remove(struct denali_nand_info *denali); void denali_remove(struct denali_nand_info *denali);
#endif /* __DENALI_H__ */ #endif /* __DENALI_H__ */
...@@ -125,3 +125,7 @@ static struct pci_driver denali_pci_driver = { ...@@ -125,3 +125,7 @@ static struct pci_driver denali_pci_driver = {
.remove = denali_pci_remove, .remove = denali_pci_remove,
}; };
module_pci_driver(denali_pci_driver); module_pci_driver(denali_pci_driver);
MODULE_DESCRIPTION("PCI driver for Denali NAND controller");
MODULE_AUTHOR("Intel Corporation and its suppliers");
MODULE_LICENSE("GPL v2");
...@@ -448,7 +448,7 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this) ...@@ -448,7 +448,7 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
int status; int status;
DoC_WaitReady(doc); DoC_WaitReady(doc);
this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); nand_status_op(this, NULL);
DoC_WaitReady(doc); DoC_WaitReady(doc);
status = (int)this->read_byte(mtd); status = (int)this->read_byte(mtd);
...@@ -595,7 +595,7 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip) ...@@ -595,7 +595,7 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
/* Assert ChipEnable and deassert WriteProtect */ /* Assert ChipEnable and deassert WriteProtect */
WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect); WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect);
this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset_op(this);
doc->curchip = chip; doc->curchip = chip;
doc->curfloor = floor; doc->curfloor = floor;
......
...@@ -785,6 +785,8 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand, ...@@ -785,6 +785,8 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
dev_dbg(doc->dev, "%s: page %08x\n", __func__, page); dev_dbg(doc->dev, "%s: page %08x\n", __func__, page);
nand_read_page_op(nand, page, 0, NULL, 0);
writew(DOC_ECCCONF0_READ_MODE | writew(DOC_ECCCONF0_READ_MODE |
DOC_ECCCONF0_ECC_ENABLE | DOC_ECCCONF0_ECC_ENABLE |
DOC_ECCCONF0_UNKNOWN | DOC_ECCCONF0_UNKNOWN |
...@@ -864,7 +866,7 @@ static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand, ...@@ -864,7 +866,7 @@ static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
dev_dbg(doc->dev, "%s: page %x\n", __func__, page); dev_dbg(doc->dev, "%s: page %x\n", __func__, page);
docg4_command(mtd, NAND_CMD_READ0, nand->ecc.size, page); nand_read_page_op(nand, page, nand->ecc.size, NULL, 0);
writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0); writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0);
write_nop(docptr); write_nop(docptr);
...@@ -900,6 +902,7 @@ static int docg4_erase_block(struct mtd_info *mtd, int page) ...@@ -900,6 +902,7 @@ static int docg4_erase_block(struct mtd_info *mtd, int page)
struct docg4_priv *doc = nand_get_controller_data(nand); struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr; void __iomem *docptr = doc->virtadr;
uint16_t g4_page; uint16_t g4_page;
int status;
dev_dbg(doc->dev, "%s: page %04x\n", __func__, page); dev_dbg(doc->dev, "%s: page %04x\n", __func__, page);
...@@ -939,11 +942,15 @@ static int docg4_erase_block(struct mtd_info *mtd, int page) ...@@ -939,11 +942,15 @@ static int docg4_erase_block(struct mtd_info *mtd, int page)
poll_status(doc); poll_status(doc);
write_nop(docptr); write_nop(docptr);
return nand->waitfunc(mtd, nand); status = nand->waitfunc(mtd, nand);
if (status < 0)
return status;
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
static int write_page(struct mtd_info *mtd, struct nand_chip *nand, static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
const uint8_t *buf, bool use_ecc) const uint8_t *buf, int page, bool use_ecc)
{ {
struct docg4_priv *doc = nand_get_controller_data(nand); struct docg4_priv *doc = nand_get_controller_data(nand);
void __iomem *docptr = doc->virtadr; void __iomem *docptr = doc->virtadr;
...@@ -951,6 +958,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *nand, ...@@ -951,6 +958,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
dev_dbg(doc->dev, "%s...\n", __func__); dev_dbg(doc->dev, "%s...\n", __func__);
nand_prog_page_begin_op(nand, page, 0, NULL, 0);
writew(DOC_ECCCONF0_ECC_ENABLE | writew(DOC_ECCCONF0_ECC_ENABLE |
DOC_ECCCONF0_UNKNOWN | DOC_ECCCONF0_UNKNOWN |
DOCG4_BCH_SIZE, DOCG4_BCH_SIZE,
...@@ -995,19 +1004,19 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *nand, ...@@ -995,19 +1004,19 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
writew(0, docptr + DOC_DATAEND); writew(0, docptr + DOC_DATAEND);
write_nop(docptr); write_nop(docptr);
return 0; return nand_prog_page_end_op(nand);
} }
static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
const uint8_t *buf, int oob_required, int page) const uint8_t *buf, int oob_required, int page)
{ {
return write_page(mtd, nand, buf, false); return write_page(mtd, nand, buf, page, false);
} }
static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
const uint8_t *buf, int oob_required, int page) const uint8_t *buf, int oob_required, int page)
{ {
return write_page(mtd, nand, buf, true); return write_page(mtd, nand, buf, page, true);
} }
static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand, static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
......
...@@ -713,7 +713,7 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -713,7 +713,7 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
struct fsl_lbc_ctrl *ctrl = priv->ctrl; struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
fsl_elbc_read_buf(mtd, buf, mtd->writesize); nand_read_page_op(chip, page, 0, buf, mtd->writesize);
if (oob_required) if (oob_required)
fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
...@@ -729,10 +729,10 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -729,10 +729,10 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page) const uint8_t *buf, int oob_required, int page)
{ {
fsl_elbc_write_buf(mtd, buf, mtd->writesize); nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0; return nand_prog_page_end_op(chip);
} }
/* ECC will be calculated automatically, and errors will be detected in /* ECC will be calculated automatically, and errors will be detected in
...@@ -742,10 +742,10 @@ static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -742,10 +742,10 @@ static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offset, uint32_t data_len, uint32_t offset, uint32_t data_len,
const uint8_t *buf, int oob_required, int page) const uint8_t *buf, int oob_required, int page)
{ {
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
fsl_elbc_write_buf(mtd, buf, mtd->writesize); fsl_elbc_write_buf(mtd, buf, mtd->writesize);
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
return nand_prog_page_end_op(chip);
return 0;
} }
static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
......
...@@ -688,7 +688,7 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -688,7 +688,7 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
struct fsl_ifc_ctrl *ctrl = priv->ctrl; struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl; struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
fsl_ifc_read_buf(mtd, buf, mtd->writesize); nand_read_page_op(chip, page, 0, buf, mtd->writesize);
if (oob_required) if (oob_required)
fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
...@@ -711,10 +711,10 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -711,10 +711,10 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip, static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page) const uint8_t *buf, int oob_required, int page)
{ {
fsl_ifc_write_buf(mtd, buf, mtd->writesize); nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0; return nand_prog_page_end_op(chip);
} }
static int fsl_ifc_chip_init_tail(struct mtd_info *mtd) static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
...@@ -916,6 +916,13 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) ...@@ -916,6 +916,13 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
if (ctrl->version >= FSL_IFC_VERSION_1_1_0) if (ctrl->version >= FSL_IFC_VERSION_1_1_0)
fsl_ifc_sram_init(priv); fsl_ifc_sram_init(priv);
/*
* As IFC version 2.0.0 has 16KB of internal SRAM as compared to older
* versions which had 8KB. Hence bufnum mask needs to be updated.
*/
if (ctrl->version >= FSL_IFC_VERSION_2_0_0)
priv->bufnum_mask = (priv->bufnum_mask * 2) + 1;
return 0; return 0;
} }
......
...@@ -684,8 +684,8 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -684,8 +684,8 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
int eccbytes = chip->ecc.bytes; int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps; int eccsteps = chip->ecc.steps;
uint8_t *p = buf; uint8_t *p = buf;
uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_calc = chip->ecc.calc_buf;
uint8_t *ecc_code = chip->buffers->ecccode; uint8_t *ecc_code = chip->ecc.code_buf;
int off, len, group = 0; int off, len, group = 0;
/* /*
* ecc_oob is intentionally taken as uint16_t. In 16bit devices, we * ecc_oob is intentionally taken as uint16_t. In 16bit devices, we
...@@ -697,7 +697,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -697,7 +697,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
unsigned int max_bitflips = 0; unsigned int max_bitflips = 0;
for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page); nand_read_page_op(chip, page, s * eccsize, NULL, 0);
chip->ecc.hwctl(mtd, NAND_ECC_READ); chip->ecc.hwctl(mtd, NAND_ECC_READ);
chip->read_buf(mtd, p, eccsize); chip->read_buf(mtd, p, eccsize);
...@@ -720,8 +720,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -720,8 +720,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
if (chip->options & NAND_BUSWIDTH_16) if (chip->options & NAND_BUSWIDTH_16)
len = roundup(len, 2); len = roundup(len, 2);
chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page); nand_read_oob_op(chip, page, off, oob + j, len);
chip->read_buf(mtd, oob + j, len);
j += len; j += len;
} }
......
...@@ -1029,11 +1029,13 @@ static void block_mark_swapping(struct gpmi_nand_data *this, ...@@ -1029,11 +1029,13 @@ static void block_mark_swapping(struct gpmi_nand_data *this,
p[1] = (p[1] & mask) | (from_oob >> (8 - bit)); p[1] = (p[1] & mask) | (from_oob >> (8 - bit));
} }
static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, static int gpmi_ecc_read_page_data(struct nand_chip *chip,
uint8_t *buf, int oob_required, int page) uint8_t *buf, int oob_required,
int page)
{ {
struct gpmi_nand_data *this = nand_get_controller_data(chip); struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry; struct bch_geometry *nfc_geo = &this->bch_geometry;
struct mtd_info *mtd = nand_to_mtd(chip);
void *payload_virt; void *payload_virt;
dma_addr_t payload_phys; dma_addr_t payload_phys;
void *auxiliary_virt; void *auxiliary_virt;
...@@ -1094,8 +1096,8 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1094,8 +1096,8 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
eccbytes = DIV_ROUND_UP(offset + eccbits, 8); eccbytes = DIV_ROUND_UP(offset + eccbits, 8);
offset /= 8; offset /= 8;
eccbytes -= offset; eccbytes -= offset;
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); nand_change_read_column_op(chip, offset, eccbuf,
chip->read_buf(mtd, eccbuf, eccbytes); eccbytes, false);
/* /*
* ECC data are not byte aligned and we may have * ECC data are not byte aligned and we may have
...@@ -1176,6 +1178,14 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1176,6 +1178,14 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return max_bitflips; return max_bitflips;
} }
static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
nand_read_page_op(chip, page, 0, NULL, 0);
return gpmi_ecc_read_page_data(chip, buf, oob_required, page);
}
/* Fake a virtual small page for the subpage read */ /* Fake a virtual small page for the subpage read */
static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offs, uint32_t len, uint8_t *buf, int page) uint32_t offs, uint32_t len, uint8_t *buf, int page)
...@@ -1220,12 +1230,12 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1220,12 +1230,12 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
meta = geo->metadata_size; meta = geo->metadata_size;
if (first) { if (first) {
col = meta + (size + ecc_parity_size) * first; col = meta + (size + ecc_parity_size) * first;
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
meta = 0; meta = 0;
buf = buf + first * size; buf = buf + first * size;
} }
nand_read_page_op(chip, page, col, NULL, 0);
/* Save the old environment */ /* Save the old environment */
r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0); r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0);
r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1); r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1);
...@@ -1254,7 +1264,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1254,7 +1264,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
/* Read the subpage now */ /* Read the subpage now */
this->swap_block_mark = false; this->swap_block_mark = false;
max_bitflips = gpmi_ecc_read_page(mtd, chip, buf, 0, page); max_bitflips = gpmi_ecc_read_page_data(chip, buf, 0, page);
/* Restore */ /* Restore */
writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0); writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0);
...@@ -1277,6 +1287,9 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1277,6 +1287,9 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
int ret; int ret;
dev_dbg(this->dev, "ecc write page.\n"); dev_dbg(this->dev, "ecc write page.\n");
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
if (this->swap_block_mark) { if (this->swap_block_mark) {
/* /*
* If control arrives here, we're doing block mark swapping. * If control arrives here, we're doing block mark swapping.
...@@ -1338,7 +1351,10 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1338,7 +1351,10 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
payload_virt, payload_phys); payload_virt, payload_phys);
} }
return 0; if (ret)
return ret;
return nand_prog_page_end_op(chip);
} }
/* /*
...@@ -1411,7 +1427,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1411,7 +1427,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
memset(chip->oob_poi, ~0, mtd->oobsize); memset(chip->oob_poi, ~0, mtd->oobsize);
/* Read out the conventional OOB. */ /* Read out the conventional OOB. */
chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
/* /*
...@@ -1421,7 +1437,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1421,7 +1437,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
*/ */
if (GPMI_IS_MX23(this)) { if (GPMI_IS_MX23(this)) {
/* Read the block mark into the first byte of the OOB buffer. */ /* Read the block mark into the first byte of the OOB buffer. */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
chip->oob_poi[0] = chip->read_byte(mtd); chip->oob_poi[0] = chip->read_byte(mtd);
} }
...@@ -1432,7 +1448,6 @@ static int ...@@ -1432,7 +1448,6 @@ static int
gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
{ {
struct mtd_oob_region of = { }; struct mtd_oob_region of = { };
int status = 0;
/* Do we have available oob area? */ /* Do we have available oob area? */
mtd_ooblayout_free(mtd, 0, &of); mtd_ooblayout_free(mtd, 0, &of);
...@@ -1442,12 +1457,8 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) ...@@ -1442,12 +1457,8 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
if (!nand_is_slc(chip)) if (!nand_is_slc(chip))
return -EPERM; return -EPERM;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + of.offset, page); return nand_prog_page_op(chip, page, mtd->writesize + of.offset,
chip->write_buf(mtd, chip->oob_poi + of.offset, of.length); chip->oob_poi + of.offset, of.length);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
/* /*
...@@ -1477,8 +1488,8 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, ...@@ -1477,8 +1488,8 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
uint8_t *oob = chip->oob_poi; uint8_t *oob = chip->oob_poi;
int step; int step;
chip->read_buf(mtd, tmp_buf, nand_read_page_op(chip, page, 0, tmp_buf,
mtd->writesize + mtd->oobsize); mtd->writesize + mtd->oobsize);
/* /*
* If required, swap the bad block marker and the data stored in the * If required, swap the bad block marker and the data stored in the
...@@ -1487,12 +1498,8 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, ...@@ -1487,12 +1498,8 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
* See the layout description for a detailed explanation on why this * See the layout description for a detailed explanation on why this
* is needed. * is needed.
*/ */
if (this->swap_block_mark) { if (this->swap_block_mark)
u8 swap = tmp_buf[0]; swap(tmp_buf[0], tmp_buf[mtd->writesize]);
tmp_buf[0] = tmp_buf[mtd->writesize];
tmp_buf[mtd->writesize] = swap;
}
/* /*
* Copy the metadata section into the oob buffer (this section is * Copy the metadata section into the oob buffer (this section is
...@@ -1615,31 +1622,22 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, ...@@ -1615,31 +1622,22 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
* See the layout description for a detailed explanation on why this * See the layout description for a detailed explanation on why this
* is needed. * is needed.
*/ */
if (this->swap_block_mark) { if (this->swap_block_mark)
u8 swap = tmp_buf[0]; swap(tmp_buf[0], tmp_buf[mtd->writesize]);
tmp_buf[0] = tmp_buf[mtd->writesize];
tmp_buf[mtd->writesize] = swap;
}
chip->write_buf(mtd, tmp_buf, mtd->writesize + mtd->oobsize); return nand_prog_page_op(chip, page, 0, tmp_buf,
mtd->writesize + mtd->oobsize);
return 0;
} }
static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page); return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page);
} }
static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page); return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page);
} }
...@@ -1649,7 +1647,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1649,7 +1647,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
struct gpmi_nand_data *this = nand_get_controller_data(chip); struct gpmi_nand_data *this = nand_get_controller_data(chip);
int ret = 0; int ret = 0;
uint8_t *block_mark; uint8_t *block_mark;
int column, page, status, chipnr; int column, page, chipnr;
chipnr = (int)(ofs >> chip->chip_shift); chipnr = (int)(ofs >> chip->chip_shift);
chip->select_chip(mtd, chipnr); chip->select_chip(mtd, chipnr);
...@@ -1663,13 +1661,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1663,13 +1661,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* Shift to get page */ /* Shift to get page */
page = (int)(ofs >> chip->page_shift); page = (int)(ofs >> chip->page_shift);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page); ret = nand_prog_page_op(chip, page, column, block_mark, 1);
chip->write_buf(mtd, block_mark, 1);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
ret = -EIO;
chip->select_chip(mtd, -1); chip->select_chip(mtd, -1);
...@@ -1712,7 +1704,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) ...@@ -1712,7 +1704,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
unsigned int search_area_size_in_strides; unsigned int search_area_size_in_strides;
unsigned int stride; unsigned int stride;
unsigned int page; unsigned int page;
uint8_t *buffer = chip->buffers->databuf; uint8_t *buffer = chip->data_buf;
int saved_chip_number; int saved_chip_number;
int found_an_ncb_fingerprint = false; int found_an_ncb_fingerprint = false;
...@@ -1737,7 +1729,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) ...@@ -1737,7 +1729,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
* Read the NCB fingerprint. The fingerprint is four bytes long * Read the NCB fingerprint. The fingerprint is four bytes long
* and starts in the 12th byte of the page. * and starts in the 12th byte of the page.
*/ */
chip->cmdfunc(mtd, NAND_CMD_READ0, 12, page); nand_read_page_op(chip, page, 12, NULL, 0);
chip->read_buf(mtd, buffer, strlen(fingerprint)); chip->read_buf(mtd, buffer, strlen(fingerprint));
/* Look for the fingerprint. */ /* Look for the fingerprint. */
...@@ -1771,7 +1763,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) ...@@ -1771,7 +1763,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
unsigned int block; unsigned int block;
unsigned int stride; unsigned int stride;
unsigned int page; unsigned int page;
uint8_t *buffer = chip->buffers->databuf; uint8_t *buffer = chip->data_buf;
int saved_chip_number; int saved_chip_number;
int status; int status;
...@@ -1797,17 +1789,10 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) ...@@ -1797,17 +1789,10 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
dev_dbg(dev, "Erasing the search area...\n"); dev_dbg(dev, "Erasing the search area...\n");
for (block = 0; block < search_area_size_in_blocks; block++) { for (block = 0; block < search_area_size_in_blocks; block++) {
/* Compute the page address. */
page = block * block_size_in_pages;
/* Erase this block. */ /* Erase this block. */
dev_dbg(dev, "\tErasing block 0x%x\n", block); dev_dbg(dev, "\tErasing block 0x%x\n", block);
chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); status = nand_erase_op(chip, block);
chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); if (status)
/* Wait for the erase to finish. */
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
dev_err(dev, "[%s] Erase failed.\n", __func__); dev_err(dev, "[%s] Erase failed.\n", __func__);
} }
...@@ -1823,13 +1808,9 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) ...@@ -1823,13 +1808,9 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
/* Write the first page of the current stride. */ /* Write the first page of the current stride. */
dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page); dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
/* Wait for the write to finish. */ status = chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
status = chip->waitfunc(mtd, chip); if (status)
if (status & NAND_STATUS_FAIL)
dev_err(dev, "[%s] Write failed.\n", __func__); dev_err(dev, "[%s] Write failed.\n", __func__);
} }
...@@ -1884,7 +1865,7 @@ static int mx23_boot_init(struct gpmi_nand_data *this) ...@@ -1884,7 +1865,7 @@ static int mx23_boot_init(struct gpmi_nand_data *this)
/* Send the command to read the conventional block mark. */ /* Send the command to read the conventional block mark. */
chip->select_chip(mtd, chipnr); chip->select_chip(mtd, chipnr);
chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
block_mark = chip->read_byte(mtd); block_mark = chip->read_byte(mtd);
chip->select_chip(mtd, -1); chip->select_chip(mtd, -1);
......
...@@ -268,31 +268,31 @@ struct timing_threshold { ...@@ -268,31 +268,31 @@ struct timing_threshold {
}; };
/* Common Services */ /* Common Services */
extern int common_nfc_set_geometry(struct gpmi_nand_data *); int common_nfc_set_geometry(struct gpmi_nand_data *);
extern struct dma_chan *get_dma_chan(struct gpmi_nand_data *); struct dma_chan *get_dma_chan(struct gpmi_nand_data *);
extern void prepare_data_dma(struct gpmi_nand_data *, void prepare_data_dma(struct gpmi_nand_data *,
enum dma_data_direction dr); enum dma_data_direction dr);
extern int start_dma_without_bch_irq(struct gpmi_nand_data *, int start_dma_without_bch_irq(struct gpmi_nand_data *,
struct dma_async_tx_descriptor *); struct dma_async_tx_descriptor *);
extern int start_dma_with_bch_irq(struct gpmi_nand_data *, int start_dma_with_bch_irq(struct gpmi_nand_data *,
struct dma_async_tx_descriptor *); struct dma_async_tx_descriptor *);
/* GPMI-NAND helper function library */ /* GPMI-NAND helper function library */
extern int gpmi_init(struct gpmi_nand_data *); int gpmi_init(struct gpmi_nand_data *);
extern int gpmi_extra_init(struct gpmi_nand_data *); int gpmi_extra_init(struct gpmi_nand_data *);
extern void gpmi_clear_bch(struct gpmi_nand_data *); void gpmi_clear_bch(struct gpmi_nand_data *);
extern void gpmi_dump_info(struct gpmi_nand_data *); void gpmi_dump_info(struct gpmi_nand_data *);
extern int bch_set_geometry(struct gpmi_nand_data *); int bch_set_geometry(struct gpmi_nand_data *);
extern int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip); int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
extern int gpmi_send_command(struct gpmi_nand_data *); int gpmi_send_command(struct gpmi_nand_data *);
extern void gpmi_begin(struct gpmi_nand_data *); void gpmi_begin(struct gpmi_nand_data *);
extern void gpmi_end(struct gpmi_nand_data *); void gpmi_end(struct gpmi_nand_data *);
extern int gpmi_read_data(struct gpmi_nand_data *); int gpmi_read_data(struct gpmi_nand_data *);
extern int gpmi_send_data(struct gpmi_nand_data *); int gpmi_send_data(struct gpmi_nand_data *);
extern int gpmi_send_page(struct gpmi_nand_data *, int gpmi_send_page(struct gpmi_nand_data *,
dma_addr_t payload, dma_addr_t auxiliary); dma_addr_t payload, dma_addr_t auxiliary);
extern int gpmi_read_page(struct gpmi_nand_data *, int gpmi_read_page(struct gpmi_nand_data *,
dma_addr_t payload, dma_addr_t auxiliary); dma_addr_t payload, dma_addr_t auxiliary);
void gpmi_copy_bits(u8 *dst, size_t dst_bit_off, void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
const u8 *src, size_t src_bit_off, const u8 *src, size_t src_bit_off,
......
...@@ -544,7 +544,7 @@ static int hisi_nand_read_page_hwecc(struct mtd_info *mtd, ...@@ -544,7 +544,7 @@ static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc; int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc;
int stat_1, stat_2; int stat_1, stat_2;
chip->read_buf(mtd, buf, mtd->writesize); nand_read_page_op(chip, page, 0, buf, mtd->writesize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
/* errors which can not be corrected by ECC */ /* errors which can not be corrected by ECC */
...@@ -574,8 +574,7 @@ static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -574,8 +574,7 @@ static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
{ {
struct hinfc_host *host = nand_get_controller_data(chip); struct hinfc_host *host = nand_get_controller_data(chip);
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
if (host->irq_status & HINFC504_INTS_UE) { if (host->irq_status & HINFC504_INTS_UE) {
host->irq_status = 0; host->irq_status = 0;
...@@ -590,11 +589,11 @@ static int hisi_nand_write_page_hwecc(struct mtd_info *mtd, ...@@ -590,11 +589,11 @@ static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf, int oob_required, struct nand_chip *chip, const uint8_t *buf, int oob_required,
int page) int page)
{ {
chip->write_buf(mtd, buf, mtd->writesize); nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
if (oob_required) if (oob_required)
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0; return nand_prog_page_end_op(chip);
} }
static void hisi_nfc_host_init(struct hinfc_host *host) static void hisi_nfc_host_init(struct hinfc_host *host)
......
...@@ -313,6 +313,7 @@ static int jz_nand_detect_bank(struct platform_device *pdev, ...@@ -313,6 +313,7 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
uint32_t ctrl; uint32_t ctrl;
struct nand_chip *chip = &nand->chip; struct nand_chip *chip = &nand->chip;
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
u8 id[2];
/* Request I/O resource. */ /* Request I/O resource. */
sprintf(res_name, "bank%d", bank); sprintf(res_name, "bank%d", bank);
...@@ -335,17 +336,16 @@ static int jz_nand_detect_bank(struct platform_device *pdev, ...@@ -335,17 +336,16 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
/* Retrieve the IDs from the first chip. */ /* Retrieve the IDs from the first chip. */
chip->select_chip(mtd, 0); chip->select_chip(mtd, 0);
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset_op(chip);
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); nand_readid_op(chip, 0, id, sizeof(id));
*nand_maf_id = chip->read_byte(mtd); *nand_maf_id = id[0];
*nand_dev_id = chip->read_byte(mtd); *nand_dev_id = id[1];
} else { } else {
/* Detect additional chip. */ /* Detect additional chip. */
chip->select_chip(mtd, chipnr); chip->select_chip(mtd, chipnr);
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset_op(chip);
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); nand_readid_op(chip, 0, id, sizeof(id));
if (*nand_maf_id != chip->read_byte(mtd) if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) {
|| *nand_dev_id != chip->read_byte(mtd)) {
ret = -ENODEV; ret = -ENODEV;
goto notfound_id; goto notfound_id;
} }
......
...@@ -461,7 +461,7 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -461,7 +461,7 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
} }
/* Writing Command and Address */ /* Writing Command and Address */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
/* For all sub-pages */ /* For all sub-pages */
for (i = 0; i < host->mlcsubpages; i++) { for (i = 0; i < host->mlcsubpages; i++) {
...@@ -522,6 +522,8 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd, ...@@ -522,6 +522,8 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
memcpy(dma_buf, buf, mtd->writesize); memcpy(dma_buf, buf, mtd->writesize);
} }
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
for (i = 0; i < host->mlcsubpages; i++) { for (i = 0; i < host->mlcsubpages; i++) {
/* Start Encode */ /* Start Encode */
writeb(0x00, MLC_ECC_ENC_REG(host->io_base)); writeb(0x00, MLC_ECC_ENC_REG(host->io_base));
...@@ -550,7 +552,8 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd, ...@@ -550,7 +552,8 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
/* Wait for Controller Ready */ /* Wait for Controller Ready */
lpc32xx_waitfunc_controller(mtd, chip); lpc32xx_waitfunc_controller(mtd, chip);
} }
return 0;
return nand_prog_page_end_op(chip);
} }
static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip, static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
......
...@@ -399,10 +399,7 @@ static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int ...@@ -399,10 +399,7 @@ static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int
static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd, static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
struct nand_chip *chip, int page) struct nand_chip *chip, int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
} }
/* /*
...@@ -411,17 +408,8 @@ static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd, ...@@ -411,17 +408,8 @@ static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd, static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
struct nand_chip *chip, int page) struct nand_chip *chip, int page)
{ {
int status; return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
mtd->oobsize);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
/* Send command to program the OOB data */
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
/* /*
...@@ -632,7 +620,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd, ...@@ -632,7 +620,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE]; uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE];
/* Issue read command */ /* Issue read command */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
/* Read data and oob, calculate ECC */ /* Read data and oob, calculate ECC */
status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1); status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
...@@ -675,7 +663,7 @@ static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd, ...@@ -675,7 +663,7 @@ static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
int page) int page)
{ {
/* Issue read command */ /* Issue read command */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
/* Raw reads can just use the FIFO interface */ /* Raw reads can just use the FIFO interface */
chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps); chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
...@@ -698,6 +686,8 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd, ...@@ -698,6 +686,8 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
uint8_t *pb; uint8_t *pb;
int error; int error;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
/* Write data, calculate ECC on outbound data */ /* Write data, calculate ECC on outbound data */
error = lpc32xx_xfer(mtd, (uint8_t *)buf, chip->ecc.steps, 0); error = lpc32xx_xfer(mtd, (uint8_t *)buf, chip->ecc.steps, 0);
if (error) if (error)
...@@ -716,7 +706,8 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd, ...@@ -716,7 +706,8 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
/* Write ECC data to device */ /* Write ECC data to device */
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
return nand_prog_page_end_op(chip);
} }
/* /*
...@@ -729,9 +720,11 @@ static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd, ...@@ -729,9 +720,11 @@ static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
int oob_required, int page) int oob_required, int page)
{ {
/* Raw writes can just use the FIFO interface */ /* Raw writes can just use the FIFO interface */
chip->write_buf(mtd, buf, chip->ecc.size * chip->ecc.steps); nand_prog_page_begin_op(chip, page, 0, buf,
chip->ecc.size * chip->ecc.steps);
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
return nand_prog_page_end_op(chip);
} }
static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host) static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host)
......
此差异已折叠。
...@@ -34,34 +34,28 @@ ...@@ -34,34 +34,28 @@
#define ECC_ENCCON (0x00) #define ECC_ENCCON (0x00)
#define ECC_ENCCNFG (0x04) #define ECC_ENCCNFG (0x04)
#define ECC_MODE_SHIFT (5)
#define ECC_MS_SHIFT (16) #define ECC_MS_SHIFT (16)
#define ECC_ENCDIADDR (0x08) #define ECC_ENCDIADDR (0x08)
#define ECC_ENCIDLE (0x0C) #define ECC_ENCIDLE (0x0C)
#define ECC_ENCIRQ_EN (0x80)
#define ECC_ENCIRQ_STA (0x84)
#define ECC_DECCON (0x100) #define ECC_DECCON (0x100)
#define ECC_DECCNFG (0x104) #define ECC_DECCNFG (0x104)
#define DEC_EMPTY_EN BIT(31) #define DEC_EMPTY_EN BIT(31)
#define DEC_CNFG_CORRECT (0x3 << 12) #define DEC_CNFG_CORRECT (0x3 << 12)
#define ECC_DECIDLE (0x10C) #define ECC_DECIDLE (0x10C)
#define ECC_DECENUM0 (0x114) #define ECC_DECENUM0 (0x114)
#define ECC_DECDONE (0x124)
#define ECC_DECIRQ_EN (0x200)
#define ECC_DECIRQ_STA (0x204)
#define ECC_TIMEOUT (500000) #define ECC_TIMEOUT (500000)
#define ECC_IDLE_REG(op) ((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE) #define ECC_IDLE_REG(op) ((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE)
#define ECC_CTL_REG(op) ((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON) #define ECC_CTL_REG(op) ((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON)
#define ECC_IRQ_REG(op) ((op) == ECC_ENCODE ? \
ECC_ENCIRQ_EN : ECC_DECIRQ_EN)
struct mtk_ecc_caps { struct mtk_ecc_caps {
u32 err_mask; u32 err_mask;
const u8 *ecc_strength; const u8 *ecc_strength;
const u32 *ecc_regs;
u8 num_ecc_strength; u8 num_ecc_strength;
u32 encode_parity_reg0; u8 ecc_mode_shift;
u32 parity_bits;
int pg_irq_sel; int pg_irq_sel;
}; };
...@@ -89,6 +83,46 @@ static const u8 ecc_strength_mt2712[] = { ...@@ -89,6 +83,46 @@ static const u8 ecc_strength_mt2712[] = {
40, 44, 48, 52, 56, 60, 68, 72, 80 40, 44, 48, 52, 56, 60, 68, 72, 80
}; };
static const u8 ecc_strength_mt7622[] = {
4, 6, 8, 10, 12, 14, 16
};
enum mtk_ecc_regs {
ECC_ENCPAR00,
ECC_ENCIRQ_EN,
ECC_ENCIRQ_STA,
ECC_DECDONE,
ECC_DECIRQ_EN,
ECC_DECIRQ_STA,
};
static int mt2701_ecc_regs[] = {
[ECC_ENCPAR00] = 0x10,
[ECC_ENCIRQ_EN] = 0x80,
[ECC_ENCIRQ_STA] = 0x84,
[ECC_DECDONE] = 0x124,
[ECC_DECIRQ_EN] = 0x200,
[ECC_DECIRQ_STA] = 0x204,
};
static int mt2712_ecc_regs[] = {
[ECC_ENCPAR00] = 0x300,
[ECC_ENCIRQ_EN] = 0x80,
[ECC_ENCIRQ_STA] = 0x84,
[ECC_DECDONE] = 0x124,
[ECC_DECIRQ_EN] = 0x200,
[ECC_DECIRQ_STA] = 0x204,
};
static int mt7622_ecc_regs[] = {
[ECC_ENCPAR00] = 0x10,
[ECC_ENCIRQ_EN] = 0x30,
[ECC_ENCIRQ_STA] = 0x34,
[ECC_DECDONE] = 0x11c,
[ECC_DECIRQ_EN] = 0x140,
[ECC_DECIRQ_STA] = 0x144,
};
static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc, static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
enum mtk_ecc_operation op) enum mtk_ecc_operation op)
{ {
...@@ -107,32 +141,30 @@ static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc, ...@@ -107,32 +141,30 @@ static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
static irqreturn_t mtk_ecc_irq(int irq, void *id) static irqreturn_t mtk_ecc_irq(int irq, void *id)
{ {
struct mtk_ecc *ecc = id; struct mtk_ecc *ecc = id;
enum mtk_ecc_operation op;
u32 dec, enc; u32 dec, enc;
dec = readw(ecc->regs + ECC_DECIRQ_STA) & ECC_IRQ_EN; dec = readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECIRQ_STA])
& ECC_IRQ_EN;
if (dec) { if (dec) {
op = ECC_DECODE; dec = readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECDONE]);
dec = readw(ecc->regs + ECC_DECDONE);
if (dec & ecc->sectors) { if (dec & ecc->sectors) {
/* /*
* Clear decode IRQ status once again to ensure that * Clear decode IRQ status once again to ensure that
* there will be no extra IRQ. * there will be no extra IRQ.
*/ */
readw(ecc->regs + ECC_DECIRQ_STA); readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECIRQ_STA]);
ecc->sectors = 0; ecc->sectors = 0;
complete(&ecc->done); complete(&ecc->done);
} else { } else {
return IRQ_HANDLED; return IRQ_HANDLED;
} }
} else { } else {
enc = readl(ecc->regs + ECC_ENCIRQ_STA) & ECC_IRQ_EN; enc = readl(ecc->regs + ecc->caps->ecc_regs[ECC_ENCIRQ_STA])
if (enc) { & ECC_IRQ_EN;
op = ECC_ENCODE; if (enc)
complete(&ecc->done); complete(&ecc->done);
} else { else
return IRQ_NONE; return IRQ_NONE;
}
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -160,7 +192,7 @@ static int mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config) ...@@ -160,7 +192,7 @@ static int mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
/* configure ECC encoder (in bits) */ /* configure ECC encoder (in bits) */
enc_sz = config->len << 3; enc_sz = config->len << 3;
reg = ecc_bit | (config->mode << ECC_MODE_SHIFT); reg = ecc_bit | (config->mode << ecc->caps->ecc_mode_shift);
reg |= (enc_sz << ECC_MS_SHIFT); reg |= (enc_sz << ECC_MS_SHIFT);
writel(reg, ecc->regs + ECC_ENCCNFG); writel(reg, ecc->regs + ECC_ENCCNFG);
...@@ -171,9 +203,9 @@ static int mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config) ...@@ -171,9 +203,9 @@ static int mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
} else { } else {
/* configure ECC decoder (in bits) */ /* configure ECC decoder (in bits) */
dec_sz = (config->len << 3) + dec_sz = (config->len << 3) +
config->strength * ECC_PARITY_BITS; config->strength * ecc->caps->parity_bits;
reg = ecc_bit | (config->mode << ECC_MODE_SHIFT); reg = ecc_bit | (config->mode << ecc->caps->ecc_mode_shift);
reg |= (dec_sz << ECC_MS_SHIFT) | DEC_CNFG_CORRECT; reg |= (dec_sz << ECC_MS_SHIFT) | DEC_CNFG_CORRECT;
reg |= DEC_EMPTY_EN; reg |= DEC_EMPTY_EN;
writel(reg, ecc->regs + ECC_DECCNFG); writel(reg, ecc->regs + ECC_DECCNFG);
...@@ -291,7 +323,12 @@ int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config) ...@@ -291,7 +323,12 @@ int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
*/ */
if (ecc->caps->pg_irq_sel && config->mode == ECC_NFI_MODE) if (ecc->caps->pg_irq_sel && config->mode == ECC_NFI_MODE)
reg_val |= ECC_PG_IRQ_SEL; reg_val |= ECC_PG_IRQ_SEL;
writew(reg_val, ecc->regs + ECC_IRQ_REG(op)); if (op == ECC_ENCODE)
writew(reg_val, ecc->regs +
ecc->caps->ecc_regs[ECC_ENCIRQ_EN]);
else
writew(reg_val, ecc->regs +
ecc->caps->ecc_regs[ECC_DECIRQ_EN]);
} }
writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op)); writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
...@@ -310,13 +347,17 @@ void mtk_ecc_disable(struct mtk_ecc *ecc) ...@@ -310,13 +347,17 @@ void mtk_ecc_disable(struct mtk_ecc *ecc)
/* disable it */ /* disable it */
mtk_ecc_wait_idle(ecc, op); mtk_ecc_wait_idle(ecc, op);
if (op == ECC_DECODE) if (op == ECC_DECODE) {
/* /*
* Clear decode IRQ status in case there is a timeout to wait * Clear decode IRQ status in case there is a timeout to wait
* decode IRQ. * decode IRQ.
*/ */
readw(ecc->regs + ECC_DECIRQ_STA); readw(ecc->regs + ecc->caps->ecc_regs[ECC_DECDONE]);
writew(0, ecc->regs + ECC_IRQ_REG(op)); writew(0, ecc->regs + ecc->caps->ecc_regs[ECC_DECIRQ_EN]);
} else {
writew(0, ecc->regs + ecc->caps->ecc_regs[ECC_ENCIRQ_EN]);
}
writew(ECC_OP_DISABLE, ecc->regs + ECC_CTL_REG(op)); writew(ECC_OP_DISABLE, ecc->regs + ECC_CTL_REG(op));
mutex_unlock(&ecc->lock); mutex_unlock(&ecc->lock);
...@@ -367,11 +408,11 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config, ...@@ -367,11 +408,11 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
mtk_ecc_wait_idle(ecc, ECC_ENCODE); mtk_ecc_wait_idle(ecc, ECC_ENCODE);
/* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */ /* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
len = (config->strength * ECC_PARITY_BITS + 7) >> 3; len = (config->strength * ecc->caps->parity_bits + 7) >> 3;
/* write the parity bytes generated by the ECC back to temp buffer */ /* write the parity bytes generated by the ECC back to temp buffer */
__ioread32_copy(ecc->eccdata, __ioread32_copy(ecc->eccdata,
ecc->regs + ecc->caps->encode_parity_reg0, ecc->regs + ecc->caps->ecc_regs[ECC_ENCPAR00],
round_up(len, 4)); round_up(len, 4));
/* copy into possibly unaligned OOB region with actual length */ /* copy into possibly unaligned OOB region with actual length */
...@@ -404,22 +445,42 @@ void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p) ...@@ -404,22 +445,42 @@ void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p)
} }
EXPORT_SYMBOL(mtk_ecc_adjust_strength); EXPORT_SYMBOL(mtk_ecc_adjust_strength);
unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc)
{
return ecc->caps->parity_bits;
}
EXPORT_SYMBOL(mtk_ecc_get_parity_bits);
static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = { static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
.err_mask = 0x3f, .err_mask = 0x3f,
.ecc_strength = ecc_strength_mt2701, .ecc_strength = ecc_strength_mt2701,
.ecc_regs = mt2701_ecc_regs,
.num_ecc_strength = 20, .num_ecc_strength = 20,
.encode_parity_reg0 = 0x10, .ecc_mode_shift = 5,
.parity_bits = 14,
.pg_irq_sel = 0, .pg_irq_sel = 0,
}; };
static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = { static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
.err_mask = 0x7f, .err_mask = 0x7f,
.ecc_strength = ecc_strength_mt2712, .ecc_strength = ecc_strength_mt2712,
.ecc_regs = mt2712_ecc_regs,
.num_ecc_strength = 23, .num_ecc_strength = 23,
.encode_parity_reg0 = 0x300, .ecc_mode_shift = 5,
.parity_bits = 14,
.pg_irq_sel = 1, .pg_irq_sel = 1,
}; };
static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = {
.err_mask = 0x3f,
.ecc_strength = ecc_strength_mt7622,
.ecc_regs = mt7622_ecc_regs,
.num_ecc_strength = 7,
.ecc_mode_shift = 4,
.parity_bits = 13,
.pg_irq_sel = 0,
};
static const struct of_device_id mtk_ecc_dt_match[] = { static const struct of_device_id mtk_ecc_dt_match[] = {
{ {
.compatible = "mediatek,mt2701-ecc", .compatible = "mediatek,mt2701-ecc",
...@@ -427,6 +488,9 @@ static const struct of_device_id mtk_ecc_dt_match[] = { ...@@ -427,6 +488,9 @@ static const struct of_device_id mtk_ecc_dt_match[] = {
}, { }, {
.compatible = "mediatek,mt2712-ecc", .compatible = "mediatek,mt2712-ecc",
.data = &mtk_ecc_caps_mt2712, .data = &mtk_ecc_caps_mt2712,
}, {
.compatible = "mediatek,mt7622-ecc",
.data = &mtk_ecc_caps_mt7622,
}, },
{}, {},
}; };
...@@ -452,7 +516,7 @@ static int mtk_ecc_probe(struct platform_device *pdev) ...@@ -452,7 +516,7 @@ static int mtk_ecc_probe(struct platform_device *pdev)
max_eccdata_size = ecc->caps->num_ecc_strength - 1; max_eccdata_size = ecc->caps->num_ecc_strength - 1;
max_eccdata_size = ecc->caps->ecc_strength[max_eccdata_size]; max_eccdata_size = ecc->caps->ecc_strength[max_eccdata_size];
max_eccdata_size = (max_eccdata_size * ECC_PARITY_BITS + 7) >> 3; max_eccdata_size = (max_eccdata_size * ecc->caps->parity_bits + 7) >> 3;
max_eccdata_size = round_up(max_eccdata_size, 4); max_eccdata_size = round_up(max_eccdata_size, 4);
ecc->eccdata = devm_kzalloc(dev, max_eccdata_size, GFP_KERNEL); ecc->eccdata = devm_kzalloc(dev, max_eccdata_size, GFP_KERNEL);
if (!ecc->eccdata) if (!ecc->eccdata)
......
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
#include <linux/types.h> #include <linux/types.h>
#define ECC_PARITY_BITS (14)
enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1}; enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE}; enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE};
...@@ -43,6 +41,7 @@ int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation); ...@@ -43,6 +41,7 @@ int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *); int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
void mtk_ecc_disable(struct mtk_ecc *); void mtk_ecc_disable(struct mtk_ecc *);
void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p); void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc);
struct mtk_ecc *of_mtk_ecc_get(struct device_node *); struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
void mtk_ecc_release(struct mtk_ecc *); void mtk_ecc_release(struct mtk_ecc *);
......
...@@ -97,7 +97,6 @@ ...@@ -97,7 +97,6 @@
#define MTK_TIMEOUT (500000) #define MTK_TIMEOUT (500000)
#define MTK_RESET_TIMEOUT (1000000) #define MTK_RESET_TIMEOUT (1000000)
#define MTK_MAX_SECTOR (16)
#define MTK_NAND_MAX_NSELS (2) #define MTK_NAND_MAX_NSELS (2)
#define MTK_NFC_MIN_SPARE (16) #define MTK_NFC_MIN_SPARE (16)
#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \ #define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
...@@ -109,6 +108,8 @@ struct mtk_nfc_caps { ...@@ -109,6 +108,8 @@ struct mtk_nfc_caps {
u8 num_spare_size; u8 num_spare_size;
u8 pageformat_spare_shift; u8 pageformat_spare_shift;
u8 nfi_clk_div; u8 nfi_clk_div;
u8 max_sector;
u32 max_sector_size;
}; };
struct mtk_nfc_bad_mark_ctl { struct mtk_nfc_bad_mark_ctl {
...@@ -173,6 +174,10 @@ static const u8 spare_size_mt2712[] = { ...@@ -173,6 +174,10 @@ static const u8 spare_size_mt2712[] = {
74 74
}; };
static const u8 spare_size_mt7622[] = {
16, 26, 27, 28
};
static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand) static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand)
{ {
return container_of(nand, struct mtk_nfc_nand_chip, nand); return container_of(nand, struct mtk_nfc_nand_chip, nand);
...@@ -450,7 +455,7 @@ static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd) ...@@ -450,7 +455,7 @@ static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
* set to max sector to allow the HW to continue reading over * set to max sector to allow the HW to continue reading over
* unaligned accesses * unaligned accesses
*/ */
reg = (MTK_MAX_SECTOR << CON_SEC_SHIFT) | CON_BRD; reg = (nfc->caps->max_sector << CON_SEC_SHIFT) | CON_BRD;
nfi_writel(nfc, reg, NFI_CON); nfi_writel(nfc, reg, NFI_CON);
/* trigger to fetch data */ /* trigger to fetch data */
...@@ -481,7 +486,7 @@ static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte) ...@@ -481,7 +486,7 @@ static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW; reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
nfi_writew(nfc, reg, NFI_CNFG); nfi_writew(nfc, reg, NFI_CNFG);
reg = MTK_MAX_SECTOR << CON_SEC_SHIFT | CON_BWR; reg = nfc->caps->max_sector << CON_SEC_SHIFT | CON_BWR;
nfi_writel(nfc, reg, NFI_CON); nfi_writel(nfc, reg, NFI_CON);
nfi_writew(nfc, STAR_EN, NFI_STRDATA); nfi_writew(nfc, STAR_EN, NFI_STRDATA);
...@@ -761,6 +766,8 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -761,6 +766,8 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
u32 reg; u32 reg;
int ret; int ret;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
if (!raw) { if (!raw) {
/* OOB => FDM: from register, ECC: from HW */ /* OOB => FDM: from register, ECC: from HW */
reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AUTO_FMT_EN; reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AUTO_FMT_EN;
...@@ -794,7 +801,10 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -794,7 +801,10 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
if (!raw) if (!raw)
mtk_ecc_disable(nfc->ecc); mtk_ecc_disable(nfc->ecc);
return ret; if (ret)
return ret;
return nand_prog_page_end_op(chip);
} }
static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd, static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
...@@ -832,18 +842,7 @@ static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd, ...@@ -832,18 +842,7 @@ static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
int ret; return mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
ret = mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
if (ret < 0)
return -EIO;
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
ret = chip->waitfunc(mtd, chip);
return ret & NAND_STATUS_FAIL ? -EIO : 0;
} }
static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors) static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
...@@ -892,8 +891,7 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -892,8 +891,7 @@ static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
len = sectors * chip->ecc.size + (raw ? sectors * spare : 0); len = sectors * chip->ecc.size + (raw ? sectors * spare : 0);
buf = bufpoi + start * chip->ecc.size; buf = bufpoi + start * chip->ecc.size;
if (column != 0) nand_read_page_op(chip, page, column, NULL, 0);
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1);
addr = dma_map_single(nfc->dev, buf, len, DMA_FROM_DEVICE); addr = dma_map_single(nfc->dev, buf, len, DMA_FROM_DEVICE);
rc = dma_mapping_error(nfc->dev, addr); rc = dma_mapping_error(nfc->dev, addr);
...@@ -1016,8 +1014,6 @@ static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1016,8 +1014,6 @@ static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page); return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
} }
...@@ -1126,9 +1122,11 @@ static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtd_info *mtd) ...@@ -1126,9 +1122,11 @@ static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtd_info *mtd)
{ {
struct nand_chip *nand = mtd_to_nand(mtd); struct nand_chip *nand = mtd_to_nand(mtd);
struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand); struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
struct mtk_nfc *nfc = nand_get_controller_data(nand);
u32 ecc_bytes; u32 ecc_bytes;
ecc_bytes = DIV_ROUND_UP(nand->ecc.strength * ECC_PARITY_BITS, 8); ecc_bytes = DIV_ROUND_UP(nand->ecc.strength *
mtk_ecc_get_parity_bits(nfc->ecc), 8);
fdm->reg_size = chip->spare_per_sector - ecc_bytes; fdm->reg_size = chip->spare_per_sector - ecc_bytes;
if (fdm->reg_size > NFI_FDM_MAX_SIZE) if (fdm->reg_size > NFI_FDM_MAX_SIZE)
...@@ -1208,7 +1206,8 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd) ...@@ -1208,7 +1206,8 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
* this controller only supports 512 and 1024 sizes * this controller only supports 512 and 1024 sizes
*/ */
if (nand->ecc.size < 1024) { if (nand->ecc.size < 1024) {
if (mtd->writesize > 512) { if (mtd->writesize > 512 &&
nfc->caps->max_sector_size > 512) {
nand->ecc.size = 1024; nand->ecc.size = 1024;
nand->ecc.strength <<= 1; nand->ecc.strength <<= 1;
} else { } else {
...@@ -1223,7 +1222,8 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd) ...@@ -1223,7 +1222,8 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
return ret; return ret;
/* calculate oob bytes except ecc parity data */ /* calculate oob bytes except ecc parity data */
free = ((nand->ecc.strength * ECC_PARITY_BITS) + 7) >> 3; free = (nand->ecc.strength * mtk_ecc_get_parity_bits(nfc->ecc)
+ 7) >> 3;
free = spare - free; free = spare - free;
/* /*
...@@ -1233,10 +1233,12 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd) ...@@ -1233,10 +1233,12 @@ static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
*/ */
if (free > NFI_FDM_MAX_SIZE) { if (free > NFI_FDM_MAX_SIZE) {
spare -= NFI_FDM_MAX_SIZE; spare -= NFI_FDM_MAX_SIZE;
nand->ecc.strength = (spare << 3) / ECC_PARITY_BITS; nand->ecc.strength = (spare << 3) /
mtk_ecc_get_parity_bits(nfc->ecc);
} else if (free < 0) { } else if (free < 0) {
spare -= NFI_FDM_MIN_SIZE; spare -= NFI_FDM_MIN_SIZE;
nand->ecc.strength = (spare << 3) / ECC_PARITY_BITS; nand->ecc.strength = (spare << 3) /
mtk_ecc_get_parity_bits(nfc->ecc);
} }
} }
...@@ -1389,6 +1391,8 @@ static const struct mtk_nfc_caps mtk_nfc_caps_mt2701 = { ...@@ -1389,6 +1391,8 @@ static const struct mtk_nfc_caps mtk_nfc_caps_mt2701 = {
.num_spare_size = 16, .num_spare_size = 16,
.pageformat_spare_shift = 4, .pageformat_spare_shift = 4,
.nfi_clk_div = 1, .nfi_clk_div = 1,
.max_sector = 16,
.max_sector_size = 1024,
}; };
static const struct mtk_nfc_caps mtk_nfc_caps_mt2712 = { static const struct mtk_nfc_caps mtk_nfc_caps_mt2712 = {
...@@ -1396,6 +1400,17 @@ static const struct mtk_nfc_caps mtk_nfc_caps_mt2712 = { ...@@ -1396,6 +1400,17 @@ static const struct mtk_nfc_caps mtk_nfc_caps_mt2712 = {
.num_spare_size = 19, .num_spare_size = 19,
.pageformat_spare_shift = 16, .pageformat_spare_shift = 16,
.nfi_clk_div = 2, .nfi_clk_div = 2,
.max_sector = 16,
.max_sector_size = 1024,
};
static const struct mtk_nfc_caps mtk_nfc_caps_mt7622 = {
.spare_size = spare_size_mt7622,
.num_spare_size = 4,
.pageformat_spare_shift = 4,
.nfi_clk_div = 1,
.max_sector = 8,
.max_sector_size = 512,
}; };
static const struct of_device_id mtk_nfc_id_table[] = { static const struct of_device_id mtk_nfc_id_table[] = {
...@@ -1405,6 +1420,9 @@ static const struct of_device_id mtk_nfc_id_table[] = { ...@@ -1405,6 +1420,9 @@ static const struct of_device_id mtk_nfc_id_table[] = {
}, { }, {
.compatible = "mediatek,mt2712-nfc", .compatible = "mediatek,mt2712-nfc",
.data = &mtk_nfc_caps_mt2712, .data = &mtk_nfc_caps_mt2712,
}, {
.compatible = "mediatek,mt7622-nfc",
.data = &mtk_nfc_caps_mt7622,
}, },
{} {}
}; };
...@@ -1540,7 +1558,6 @@ static int mtk_nfc_resume(struct device *dev) ...@@ -1540,7 +1558,6 @@ static int mtk_nfc_resume(struct device *dev)
struct mtk_nfc *nfc = dev_get_drvdata(dev); struct mtk_nfc *nfc = dev_get_drvdata(dev);
struct mtk_nfc_nand_chip *chip; struct mtk_nfc_nand_chip *chip;
struct nand_chip *nand; struct nand_chip *nand;
struct mtd_info *mtd;
int ret; int ret;
u32 i; u32 i;
...@@ -1553,11 +1570,8 @@ static int mtk_nfc_resume(struct device *dev) ...@@ -1553,11 +1570,8 @@ static int mtk_nfc_resume(struct device *dev)
/* reset NAND chip if VCC was powered off */ /* reset NAND chip if VCC was powered off */
list_for_each_entry(chip, &nfc->chips, node) { list_for_each_entry(chip, &nfc->chips, node) {
nand = &chip->nand; nand = &chip->nand;
mtd = nand_to_mtd(nand); for (i = 0; i < chip->nsels; i++)
for (i = 0; i < chip->nsels; i++) { nand_reset(nand, i);
nand->select_chip(mtd, i);
nand->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
}
} }
return 0; return 0;
......
此差异已折叠。
...@@ -898,7 +898,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b ...@@ -898,7 +898,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
{ {
struct nand_chip *this = mtd_to_nand(mtd); struct nand_chip *this = mtd_to_nand(mtd);
return create_bbt(mtd, this->buffers->databuf, bd, -1); return create_bbt(mtd, this->data_buf, bd, -1);
} }
/** /**
......
...@@ -66,16 +66,44 @@ struct hynix_read_retry_otp { ...@@ -66,16 +66,44 @@ struct hynix_read_retry_otp {
}; };
static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip) static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
{
u8 jedecid[5] = { };
int ret;
ret = nand_readid_op(chip, 0x40, jedecid, sizeof(jedecid));
if (ret)
return false;
return !strncmp("JEDEC", jedecid, sizeof(jedecid));
}
static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
{
struct mtd_info *mtd = nand_to_mtd(chip);
if (chip->exec_op) {
struct nand_op_instr instrs[] = {
NAND_OP_CMD(cmd, 0),
};
struct nand_operation op = NAND_OPERATION(instrs);
return nand_exec_op(chip, &op);
}
chip->cmdfunc(mtd, cmd, -1, -1);
return 0;
}
static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
u8 jedecid[6] = { }; u16 column = ((u16)addr << 8) | addr;
int i = 0;
chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1); chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
for (i = 0; i < 5; i++) chip->write_byte(mtd, val);
jedecid[i] = chip->read_byte(mtd);
return !strcmp("JEDEC", jedecid); return 0;
} }
static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
...@@ -83,14 +111,15 @@ static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) ...@@ -83,14 +111,15 @@ static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *chip = mtd_to_nand(mtd);
struct hynix_nand *hynix = nand_get_manufacturer_data(chip); struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
const u8 *values; const u8 *values;
int status; int i, ret;
int i;
values = hynix->read_retry->values + values = hynix->read_retry->values +
(retry_mode * hynix->read_retry->nregs); (retry_mode * hynix->read_retry->nregs);
/* Enter 'Set Hynix Parameters' mode */ /* Enter 'Set Hynix Parameters' mode */
chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, -1, -1); ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS);
if (ret)
return ret;
/* /*
* Configure the NAND in the requested read-retry mode. * Configure the NAND in the requested read-retry mode.
...@@ -102,21 +131,14 @@ static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) ...@@ -102,21 +131,14 @@ static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
* probably tweaked at production in this case). * probably tweaked at production in this case).
*/ */
for (i = 0; i < hynix->read_retry->nregs; i++) { for (i = 0; i < hynix->read_retry->nregs; i++) {
int column = hynix->read_retry->regs[i]; ret = hynix_nand_reg_write_op(chip, hynix->read_retry->regs[i],
values[i]);
column |= column << 8; if (ret)
chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1); return ret;
chip->write_byte(mtd, values[i]);
} }
/* Apply the new settings. */ /* Apply the new settings. */
chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1); return hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
} }
/** /**
...@@ -172,40 +194,63 @@ static int hynix_read_rr_otp(struct nand_chip *chip, ...@@ -172,40 +194,63 @@ static int hynix_read_rr_otp(struct nand_chip *chip,
const struct hynix_read_retry_otp *info, const struct hynix_read_retry_otp *info,
void *buf) void *buf)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); int i, ret;
int i;
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); ret = nand_reset_op(chip);
if (ret)
return ret;
chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, -1, -1); ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS);
if (ret)
return ret;
for (i = 0; i < info->nregs; i++) { for (i = 0; i < info->nregs; i++) {
int column = info->regs[i]; ret = hynix_nand_reg_write_op(chip, info->regs[i],
info->values[i]);
column |= column << 8; if (ret)
chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1); return ret;
chip->write_byte(mtd, info->values[i]);
} }
chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1); ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS);
if (ret)
return ret;
/* Sequence to enter OTP mode? */ /* Sequence to enter OTP mode? */
chip->cmdfunc(mtd, 0x17, -1, -1); ret = hynix_nand_cmd_op(chip, 0x17);
chip->cmdfunc(mtd, 0x04, -1, -1); if (ret)
chip->cmdfunc(mtd, 0x19, -1, -1); return ret;
ret = hynix_nand_cmd_op(chip, 0x4);
if (ret)
return ret;
ret = hynix_nand_cmd_op(chip, 0x19);
if (ret)
return ret;
/* Now read the page */ /* Now read the page */
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, info->page); ret = nand_read_page_op(chip, info->page, 0, buf, info->size);
chip->read_buf(mtd, buf, info->size); if (ret)
return ret;
/* Put everything back to normal */ /* Put everything back to normal */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); ret = nand_reset_op(chip);
chip->cmdfunc(mtd, NAND_HYNIX_CMD_SET_PARAMS, 0x38, -1); if (ret)
chip->write_byte(mtd, 0x0); return ret;
chip->cmdfunc(mtd, NAND_HYNIX_CMD_APPLY_PARAMS, -1, -1);
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, -1);
return 0; ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_SET_PARAMS);
if (ret)
return ret;
ret = hynix_nand_reg_write_op(chip, 0x38, 0);
if (ret)
return ret;
ret = hynix_nand_cmd_op(chip, NAND_HYNIX_CMD_APPLY_PARAMS);
if (ret)
return ret;
return nand_read_page_op(chip, 0, 0, NULL, 0);
} }
#define NAND_HYNIX_1XNM_RR_COUNT_OFFS 0 #define NAND_HYNIX_1XNM_RR_COUNT_OFFS 0
......
...@@ -117,16 +117,28 @@ micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -117,16 +117,28 @@ micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, uint8_t *buf, int oob_required,
int page) int page)
{ {
int status; u8 status;
int max_bitflips = 0; int ret, max_bitflips = 0;
micron_nand_on_die_ecc_setup(chip, true); ret = micron_nand_on_die_ecc_setup(chip, true);
if (ret)
return ret;
ret = nand_read_page_op(chip, page, 0, NULL, 0);
if (ret)
goto out;
ret = nand_status_op(chip, &status);
if (ret)
goto out;
ret = nand_exit_status_op(chip);
if (ret)
goto out;
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
status = chip->read_byte(mtd);
if (status & NAND_STATUS_FAIL) if (status & NAND_STATUS_FAIL)
mtd->ecc_stats.failed++; mtd->ecc_stats.failed++;
/* /*
* The internal ECC doesn't tell us the number of bitflips * The internal ECC doesn't tell us the number of bitflips
* that have been corrected, but tells us if it recommends to * that have been corrected, but tells us if it recommends to
...@@ -137,13 +149,15 @@ micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -137,13 +149,15 @@ micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
else if (status & NAND_STATUS_WRITE_RECOMMENDED) else if (status & NAND_STATUS_WRITE_RECOMMENDED)
max_bitflips = chip->ecc.strength; max_bitflips = chip->ecc.strength;
chip->cmdfunc(mtd, NAND_CMD_READ0, -1, -1); ret = nand_read_data_op(chip, buf, mtd->writesize, false);
if (!ret && oob_required)
nand_read_page_raw(mtd, chip, buf, oob_required, page); ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
false);
out:
micron_nand_on_die_ecc_setup(chip, false); micron_nand_on_die_ecc_setup(chip, false);
return max_bitflips; return ret ? ret : max_bitflips;
} }
static int static int
...@@ -151,46 +165,16 @@ micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -151,46 +165,16 @@ micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, const uint8_t *buf, int oob_required,
int page) int page)
{ {
int status; int ret;
micron_nand_on_die_ecc_setup(chip, true);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); ret = micron_nand_on_die_ecc_setup(chip, true);
nand_write_page_raw(mtd, chip, buf, oob_required, page); if (ret)
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return ret;
status = chip->waitfunc(mtd, chip);
ret = nand_write_page_raw(mtd, chip, buf, oob_required, page);
micron_nand_on_die_ecc_setup(chip, false); micron_nand_on_die_ecc_setup(chip, false);
return status & NAND_STATUS_FAIL ? -EIO : 0; return ret;
}
static int
micron_nand_read_page_raw_on_die_ecc(struct mtd_info *mtd,
struct nand_chip *chip,
uint8_t *buf, int oob_required,
int page)
{
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
nand_read_page_raw(mtd, chip, buf, oob_required, page);
return 0;
}
static int
micron_nand_write_page_raw_on_die_ecc(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf, int oob_required,
int page)
{
int status;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
nand_write_page_raw(mtd, chip, buf, oob_required, page);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
enum { enum {
...@@ -285,17 +269,14 @@ static int micron_nand_init(struct nand_chip *chip) ...@@ -285,17 +269,14 @@ static int micron_nand_init(struct nand_chip *chip)
return -EINVAL; return -EINVAL;
} }
chip->ecc.options = NAND_ECC_CUSTOM_PAGE_ACCESS;
chip->ecc.bytes = 8; chip->ecc.bytes = 8;
chip->ecc.size = 512; chip->ecc.size = 512;
chip->ecc.strength = 4; chip->ecc.strength = 4;
chip->ecc.algo = NAND_ECC_BCH; chip->ecc.algo = NAND_ECC_BCH;
chip->ecc.read_page = micron_nand_read_page_on_die_ecc; chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
chip->ecc.write_page = micron_nand_write_page_on_die_ecc; chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
chip->ecc.read_page_raw = chip->ecc.read_page_raw = nand_read_page_raw;
micron_nand_read_page_raw_on_die_ecc; chip->ecc.write_page_raw = nand_write_page_raw;
chip->ecc.write_page_raw =
micron_nand_write_page_raw_on_die_ecc;
mtd_set_ooblayout(mtd, &micron_nand_on_die_ooblayout_ops); mtd_set_ooblayout(mtd, &micron_nand_on_die_ooblayout_ops);
} }
......
...@@ -91,6 +91,25 @@ static void samsung_nand_decode_id(struct nand_chip *chip) ...@@ -91,6 +91,25 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
} }
} else { } else {
nand_decode_ext_id(chip); nand_decode_ext_id(chip);
if (nand_is_slc(chip)) {
switch (chip->id.data[1]) {
/* K9F4G08U0D-S[I|C]B0(T00) */
case 0xDC:
chip->ecc_step_ds = 512;
chip->ecc_strength_ds = 1;
break;
/* K9F1G08U0E 21nm chips do not support subpage write */
case 0xF1:
if (chip->id.len > 4 &&
(chip->id.data[4] & GENMASK(1, 0)) == 0x1)
chip->options |= NAND_NO_SUBPAGE_WRITE;
break;
default:
break;
}
}
} }
} }
......
...@@ -283,16 +283,16 @@ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode) ...@@ -283,16 +283,16 @@ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings); EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
/** /**
* onfi_init_data_interface - [NAND Interface] Initialize a data interface from * onfi_fill_data_interface - [NAND Interface] Initialize a data interface from
* given ONFI mode * given ONFI mode
* @iface: The data interface to be initialized
* @mode: The ONFI timing mode * @mode: The ONFI timing mode
*/ */
int onfi_init_data_interface(struct nand_chip *chip, int onfi_fill_data_interface(struct nand_chip *chip,
struct nand_data_interface *iface,
enum nand_data_interface_type type, enum nand_data_interface_type type,
int timing_mode) int timing_mode)
{ {
struct nand_data_interface *iface = &chip->data_interface;
if (type != NAND_SDR_IFACE) if (type != NAND_SDR_IFACE)
return -EINVAL; return -EINVAL;
...@@ -321,15 +321,4 @@ int onfi_init_data_interface(struct nand_chip *chip, ...@@ -321,15 +321,4 @@ int onfi_init_data_interface(struct nand_chip *chip,
return 0; return 0;
} }
EXPORT_SYMBOL(onfi_init_data_interface); EXPORT_SYMBOL(onfi_fill_data_interface);
/**
* nand_get_default_data_interface - [NAND Interface] Retrieve NAND
* data interface for mode 0. This is used as default timing after
* reset.
*/
const struct nand_data_interface *nand_get_default_data_interface(void)
{
return &onfi_sdr_timings[0];
}
EXPORT_SYMBOL(nand_get_default_data_interface);
...@@ -1530,7 +1530,9 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1530,7 +1530,9 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, int page) const uint8_t *buf, int oob_required, int page)
{ {
int ret; int ret;
uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_calc = chip->ecc.calc_buf;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
/* Enable GPMC ecc engine */ /* Enable GPMC ecc engine */
chip->ecc.hwctl(mtd, NAND_ECC_WRITE); chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
...@@ -1548,7 +1550,8 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1548,7 +1550,8 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
/* Write ecc vector to OOB area */ /* Write ecc vector to OOB area */
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
return nand_prog_page_end_op(chip);
} }
/** /**
...@@ -1568,7 +1571,7 @@ static int omap_write_subpage_bch(struct mtd_info *mtd, ...@@ -1568,7 +1571,7 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
u32 data_len, const u8 *buf, u32 data_len, const u8 *buf,
int oob_required, int page) int oob_required, int page)
{ {
u8 *ecc_calc = chip->buffers->ecccalc; u8 *ecc_calc = chip->ecc.calc_buf;
int ecc_size = chip->ecc.size; int ecc_size = chip->ecc.size;
int ecc_bytes = chip->ecc.bytes; int ecc_bytes = chip->ecc.bytes;
int ecc_steps = chip->ecc.steps; int ecc_steps = chip->ecc.steps;
...@@ -1582,6 +1585,7 @@ static int omap_write_subpage_bch(struct mtd_info *mtd, ...@@ -1582,6 +1585,7 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
* ECC is calculated for all subpages but we choose * ECC is calculated for all subpages but we choose
* only what we want. * only what we want.
*/ */
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
/* Enable GPMC ECC engine */ /* Enable GPMC ECC engine */
chip->ecc.hwctl(mtd, NAND_ECC_WRITE); chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
...@@ -1605,7 +1609,7 @@ static int omap_write_subpage_bch(struct mtd_info *mtd, ...@@ -1605,7 +1609,7 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
/* copy calculated ECC for whole page to chip->buffer->oob */ /* copy calculated ECC for whole page to chip->buffer->oob */
/* this include masked-value(0xFF) for unwritten subpages */ /* this include masked-value(0xFF) for unwritten subpages */
ecc_calc = chip->buffers->ecccalc; ecc_calc = chip->ecc.calc_buf;
ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
chip->ecc.total); chip->ecc.total);
if (ret) if (ret)
...@@ -1614,7 +1618,7 @@ static int omap_write_subpage_bch(struct mtd_info *mtd, ...@@ -1614,7 +1618,7 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
/* write OOB buffer to NAND device */ /* write OOB buffer to NAND device */
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0; return nand_prog_page_end_op(chip);
} }
/** /**
...@@ -1635,11 +1639,13 @@ static int omap_write_subpage_bch(struct mtd_info *mtd, ...@@ -1635,11 +1639,13 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page) uint8_t *buf, int oob_required, int page)
{ {
uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_calc = chip->ecc.calc_buf;
uint8_t *ecc_code = chip->buffers->ecccode; uint8_t *ecc_code = chip->ecc.code_buf;
int stat, ret; int stat, ret;
unsigned int max_bitflips = 0; unsigned int max_bitflips = 0;
nand_read_page_op(chip, page, 0, NULL, 0);
/* Enable GPMC ecc engine */ /* Enable GPMC ecc engine */
chip->ecc.hwctl(mtd, NAND_ECC_READ); chip->ecc.hwctl(mtd, NAND_ECC_READ);
...@@ -1647,10 +1653,10 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1647,10 +1653,10 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, buf, mtd->writesize);
/* Read oob bytes */ /* Read oob bytes */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, nand_change_read_column_op(chip,
mtd->writesize + BADBLOCK_MARKER_LENGTH, -1); mtd->writesize + BADBLOCK_MARKER_LENGTH,
chip->read_buf(mtd, chip->oob_poi + BADBLOCK_MARKER_LENGTH, chip->oob_poi + BADBLOCK_MARKER_LENGTH,
chip->ecc.total); chip->ecc.total, false);
/* Calculate ecc bytes */ /* Calculate ecc bytes */
omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc); omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc);
......
...@@ -520,15 +520,13 @@ static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host, ...@@ -520,15 +520,13 @@ static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host,
struct nand_chip *chip = &host->chip; struct nand_chip *chip = &host->chip;
struct pxa3xx_nand_info *info = host->info_data; struct pxa3xx_nand_info *info = host->info_data;
const struct pxa3xx_nand_flash *f = NULL; const struct pxa3xx_nand_flash *f = NULL;
struct mtd_info *mtd = nand_to_mtd(&host->chip);
int i, id, ntypes; int i, id, ntypes;
u8 idbuf[2];
ntypes = ARRAY_SIZE(builtin_flash_types); ntypes = ARRAY_SIZE(builtin_flash_types);
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); nand_readid_op(chip, 0, idbuf, sizeof(idbuf));
id = idbuf[0] | (idbuf[1] << 8);
id = chip->read_byte(mtd);
id |= chip->read_byte(mtd) << 0x8;
for (i = 0; i < ntypes; i++) { for (i = 0; i < ntypes; i++) {
f = &builtin_flash_types[i]; f = &builtin_flash_types[i];
...@@ -1351,10 +1349,10 @@ static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, ...@@ -1351,10 +1349,10 @@ static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf, int oob_required, struct nand_chip *chip, const uint8_t *buf, int oob_required,
int page) int page)
{ {
chip->write_buf(mtd, buf, mtd->writesize); nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0; return nand_prog_page_end_op(chip);
} }
static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
...@@ -1364,7 +1362,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, ...@@ -1364,7 +1362,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
struct pxa3xx_nand_host *host = nand_get_controller_data(chip); struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
struct pxa3xx_nand_info *info = host->info_data; struct pxa3xx_nand_info *info = host->info_data;
chip->read_buf(mtd, buf, mtd->writesize); nand_read_page_op(chip, page, 0, buf, mtd->writesize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
if (info->retcode == ERR_CORERR && info->use_ecc) { if (info->retcode == ERR_CORERR && info->use_ecc) {
......
...@@ -1725,6 +1725,7 @@ static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1725,6 +1725,7 @@ static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
u8 *data_buf, *oob_buf = NULL; u8 *data_buf, *oob_buf = NULL;
int ret; int ret;
nand_read_page_op(chip, page, 0, NULL, 0);
data_buf = buf; data_buf = buf;
oob_buf = oob_required ? chip->oob_poi : NULL; oob_buf = oob_required ? chip->oob_poi : NULL;
...@@ -1750,6 +1751,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, ...@@ -1750,6 +1751,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
int i, ret; int i, ret;
int read_loc; int read_loc;
nand_read_page_op(chip, page, 0, NULL, 0);
data_buf = buf; data_buf = buf;
oob_buf = chip->oob_poi; oob_buf = chip->oob_poi;
...@@ -1850,6 +1852,8 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1850,6 +1852,8 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
u8 *data_buf, *oob_buf; u8 *data_buf, *oob_buf;
int i, ret; int i, ret;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
clear_read_regs(nandc); clear_read_regs(nandc);
clear_bam_transaction(nandc); clear_bam_transaction(nandc);
...@@ -1902,6 +1906,9 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1902,6 +1906,9 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
free_descs(nandc); free_descs(nandc);
if (!ret)
ret = nand_prog_page_end_op(chip);
return ret; return ret;
} }
...@@ -1916,6 +1923,7 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, ...@@ -1916,6 +1923,7 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
u8 *data_buf, *oob_buf; u8 *data_buf, *oob_buf;
int i, ret; int i, ret;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
clear_read_regs(nandc); clear_read_regs(nandc);
clear_bam_transaction(nandc); clear_bam_transaction(nandc);
...@@ -1970,6 +1978,9 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, ...@@ -1970,6 +1978,9 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
free_descs(nandc); free_descs(nandc);
if (!ret)
ret = nand_prog_page_end_op(chip);
return ret; return ret;
} }
...@@ -1990,7 +2001,7 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1990,7 +2001,7 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
struct nand_ecc_ctrl *ecc = &chip->ecc; struct nand_ecc_ctrl *ecc = &chip->ecc;
u8 *oob = chip->oob_poi; u8 *oob = chip->oob_poi;
int data_size, oob_size; int data_size, oob_size;
int ret, status = 0; int ret;
host->use_ecc = true; host->use_ecc = true;
...@@ -2027,11 +2038,7 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -2027,11 +2038,7 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
return -EIO; return -EIO;
} }
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs) static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
...@@ -2081,7 +2088,7 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -2081,7 +2088,7 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_host *host = to_qcom_nand_host(chip);
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
struct nand_ecc_ctrl *ecc = &chip->ecc; struct nand_ecc_ctrl *ecc = &chip->ecc;
int page, ret, status = 0; int page, ret;
clear_read_regs(nandc); clear_read_regs(nandc);
clear_bam_transaction(nandc); clear_bam_transaction(nandc);
...@@ -2114,11 +2121,7 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -2114,11 +2121,7 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
return -EIO; return -EIO;
} }
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
/* /*
...@@ -2636,6 +2639,9 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc, ...@@ -2636,6 +2639,9 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc,
nand_set_flash_node(chip, dn); nand_set_flash_node(chip, dn);
mtd->name = devm_kasprintf(dev, GFP_KERNEL, "qcom_nand.%d", host->cs); mtd->name = devm_kasprintf(dev, GFP_KERNEL, "qcom_nand.%d", host->cs);
if (!mtd->name)
return -ENOMEM;
mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE;
mtd->dev.parent = dev; mtd->dev.parent = dev;
......
...@@ -364,7 +364,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip) ...@@ -364,7 +364,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
struct r852_device *dev = nand_get_controller_data(chip); struct r852_device *dev = nand_get_controller_data(chip);
unsigned long timeout; unsigned long timeout;
int status; u8 status;
timeout = jiffies + (chip->state == FL_ERASING ? timeout = jiffies + (chip->state == FL_ERASING ?
msecs_to_jiffies(400) : msecs_to_jiffies(20)); msecs_to_jiffies(400) : msecs_to_jiffies(20));
...@@ -373,8 +373,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip) ...@@ -373,8 +373,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
if (chip->dev_ready(mtd)) if (chip->dev_ready(mtd))
break; break;
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); nand_status_op(chip, &status);
status = (int)chip->read_byte(mtd);
/* Unfortunelly, no way to send detailed error status... */ /* Unfortunelly, no way to send detailed error status... */
if (dev->dma_error) { if (dev->dma_error) {
...@@ -522,9 +521,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, ...@@ -522,9 +521,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip, static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
} }
/* /*
...@@ -1046,7 +1043,7 @@ static int r852_resume(struct device *device) ...@@ -1046,7 +1043,7 @@ static int r852_resume(struct device *device)
if (dev->card_registred) { if (dev->card_registred) {
r852_engine_enable(dev); r852_engine_enable(dev);
dev->chip->select_chip(mtd, 0); dev->chip->select_chip(mtd, 0);
dev->chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); nand_reset_op(dev->chip);
dev->chip->select_chip(mtd, -1); dev->chip->select_chip(mtd, -1);
} }
......
...@@ -614,7 +614,7 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va ...@@ -614,7 +614,7 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page) uint8_t *buf, int oob_required, int page)
{ {
chip->read_buf(mtd, buf, mtd->writesize); nand_read_page_op(chip, page, 0, buf, mtd->writesize);
if (oob_required) if (oob_required)
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0; return 0;
...@@ -624,9 +624,9 @@ static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -624,9 +624,9 @@ static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required, const uint8_t *buf, int oob_required,
int page) int page)
{ {
chip->write_buf(mtd, buf, mtd->writesize); nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0; return nand_prog_page_end_op(chip);
} }
static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
......
...@@ -36,7 +36,7 @@ struct sm_oob { ...@@ -36,7 +36,7 @@ struct sm_oob {
#define SM_SMALL_OOB_SIZE 8 #define SM_SMALL_OOB_SIZE 8
extern int sm_register_device(struct mtd_info *mtd, int smartmedia); int sm_register_device(struct mtd_info *mtd, int smartmedia);
static inline int sm_sector_valid(struct sm_oob *oob) static inline int sm_sector_valid(struct sm_oob *oob)
......
...@@ -958,12 +958,12 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, ...@@ -958,12 +958,12 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
int ret; int ret;
if (*cur_off != data_off) if (*cur_off != data_off)
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); nand_change_read_column_op(nand, data_off, NULL, 0, false);
sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page); sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page);
if (data_off + ecc->size != oob_off) if (data_off + ecc->size != oob_off)
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); nand_change_read_column_op(nand, oob_off, NULL, 0, false);
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
if (ret) if (ret)
...@@ -991,16 +991,15 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, ...@@ -991,16 +991,15 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
* Re-read the data with the randomizer disabled to identify * Re-read the data with the randomizer disabled to identify
* bitflips in erased pages. * bitflips in erased pages.
*/ */
if (nand->options & NAND_NEED_SCRAMBLING) { if (nand->options & NAND_NEED_SCRAMBLING)
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); nand_change_read_column_op(nand, data_off, data,
nand->read_buf(mtd, data, ecc->size); ecc->size, false);
} else { else
memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE,
ecc->size); ecc->size);
}
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); nand_change_read_column_op(nand, oob_off, oob, ecc->bytes + 4,
nand->read_buf(mtd, oob, ecc->bytes + 4); false);
ret = nand_check_erased_ecc_chunk(data, ecc->size, ret = nand_check_erased_ecc_chunk(data, ecc->size,
oob, ecc->bytes + 4, oob, ecc->bytes + 4,
...@@ -1011,7 +1010,8 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, ...@@ -1011,7 +1010,8 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size); memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
if (oob_required) { if (oob_required) {
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); nand_change_read_column_op(nand, oob_off, NULL, 0,
false);
sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
true, page); true, page);
...@@ -1038,8 +1038,8 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd, ...@@ -1038,8 +1038,8 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
return; return;
if (!cur_off || *cur_off != offset) if (!cur_off || *cur_off != offset)
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, nand_change_read_column_op(nand, mtd->writesize, NULL, 0,
offset + mtd->writesize, -1); false);
if (!randomize) if (!randomize)
sunxi_nfc_read_buf(mtd, oob + offset, len); sunxi_nfc_read_buf(mtd, oob + offset, len);
...@@ -1116,9 +1116,9 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf, ...@@ -1116,9 +1116,9 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
if (oob_required && !erased) { if (oob_required && !erased) {
/* TODO: use DMA to retrieve OOB */ /* TODO: use DMA to retrieve OOB */
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, nand_change_read_column_op(nand,
mtd->writesize + oob_off, -1); mtd->writesize + oob_off,
nand->read_buf(mtd, oob, ecc->bytes + 4); oob, ecc->bytes + 4, false);
sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i, sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i,
!i, page); !i, page);
...@@ -1143,18 +1143,17 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf, ...@@ -1143,18 +1143,17 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
/* /*
* Re-read the data with the randomizer disabled to * Re-read the data with the randomizer disabled to
* identify bitflips in erased pages. * identify bitflips in erased pages.
* TODO: use DMA to read page in raw mode
*/ */
if (randomized) { if (randomized)
/* TODO: use DMA to read page in raw mode */ nand_change_read_column_op(nand, data_off,
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data, ecc->size,
data_off, -1); false);
nand->read_buf(mtd, data, ecc->size);
}
/* TODO: use DMA to retrieve OOB */ /* TODO: use DMA to retrieve OOB */
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, nand_change_read_column_op(nand,
mtd->writesize + oob_off, -1); mtd->writesize + oob_off,
nand->read_buf(mtd, oob, ecc->bytes + 4); oob, ecc->bytes + 4, false);
ret = nand_check_erased_ecc_chunk(data, ecc->size, ret = nand_check_erased_ecc_chunk(data, ecc->size,
oob, ecc->bytes + 4, oob, ecc->bytes + 4,
...@@ -1187,12 +1186,12 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, ...@@ -1187,12 +1186,12 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
int ret; int ret;
if (data_off != *cur_off) if (data_off != *cur_off)
nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1); nand_change_write_column_op(nand, data_off, NULL, 0, false);
sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page); sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
if (data_off + ecc->size != oob_off) if (data_off + ecc->size != oob_off)
nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1); nand_change_write_column_op(nand, oob_off, NULL, 0, false);
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
if (ret) if (ret)
...@@ -1228,8 +1227,8 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd, ...@@ -1228,8 +1227,8 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
return; return;
if (!cur_off || *cur_off != offset) if (!cur_off || *cur_off != offset)
nand->cmdfunc(mtd, NAND_CMD_RNDIN, nand_change_write_column_op(nand, offset + mtd->writesize,
offset + mtd->writesize, -1); NULL, 0, false);
sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page); sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
...@@ -1246,6 +1245,8 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd, ...@@ -1246,6 +1245,8 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
int ret, i, cur_off = 0; int ret, i, cur_off = 0;
bool raw_mode = false; bool raw_mode = false;
nand_read_page_op(chip, page, 0, NULL, 0);
sunxi_nfc_hw_ecc_enable(mtd); sunxi_nfc_hw_ecc_enable(mtd);
for (i = 0; i < ecc->steps; i++) { for (i = 0; i < ecc->steps; i++) {
...@@ -1279,14 +1280,14 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd, ...@@ -1279,14 +1280,14 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
{ {
int ret; int ret;
nand_read_page_op(chip, page, 0, NULL, 0);
ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, oob_required, page, ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, oob_required, page,
chip->ecc.steps); chip->ecc.steps);
if (ret >= 0) if (ret >= 0)
return ret; return ret;
/* Fallback to PIO mode */ /* Fallback to PIO mode */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page); return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page);
} }
...@@ -1299,6 +1300,8 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd, ...@@ -1299,6 +1300,8 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
int ret, i, cur_off = 0; int ret, i, cur_off = 0;
unsigned int max_bitflips = 0; unsigned int max_bitflips = 0;
nand_read_page_op(chip, page, 0, NULL, 0);
sunxi_nfc_hw_ecc_enable(mtd); sunxi_nfc_hw_ecc_enable(mtd);
for (i = data_offs / ecc->size; for (i = data_offs / ecc->size;
...@@ -1330,13 +1333,13 @@ static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd, ...@@ -1330,13 +1333,13 @@ static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size); int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
int ret; int ret;
nand_read_page_op(chip, page, 0, NULL, 0);
ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, false, page, nchunks); ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, false, page, nchunks);
if (ret >= 0) if (ret >= 0)
return ret; return ret;
/* Fallback to PIO mode */ /* Fallback to PIO mode */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen, return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen,
buf, page); buf, page);
} }
...@@ -1349,6 +1352,8 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, ...@@ -1349,6 +1352,8 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
struct nand_ecc_ctrl *ecc = &chip->ecc; struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret, i, cur_off = 0; int ret, i, cur_off = 0;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
sunxi_nfc_hw_ecc_enable(mtd); sunxi_nfc_hw_ecc_enable(mtd);
for (i = 0; i < ecc->steps; i++) { for (i = 0; i < ecc->steps; i++) {
...@@ -1370,7 +1375,7 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, ...@@ -1370,7 +1375,7 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
sunxi_nfc_hw_ecc_disable(mtd); sunxi_nfc_hw_ecc_disable(mtd);
return 0; return nand_prog_page_end_op(chip);
} }
static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd, static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
...@@ -1382,6 +1387,8 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd, ...@@ -1382,6 +1387,8 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
struct nand_ecc_ctrl *ecc = &chip->ecc; struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret, i, cur_off = 0; int ret, i, cur_off = 0;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
sunxi_nfc_hw_ecc_enable(mtd); sunxi_nfc_hw_ecc_enable(mtd);
for (i = data_offs / ecc->size; for (i = data_offs / ecc->size;
...@@ -1400,7 +1407,7 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd, ...@@ -1400,7 +1407,7 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
sunxi_nfc_hw_ecc_disable(mtd); sunxi_nfc_hw_ecc_disable(mtd);
return 0; return nand_prog_page_end_op(chip);
} }
static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd, static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
...@@ -1430,6 +1437,8 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd, ...@@ -1430,6 +1437,8 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, i, !i, page); sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, i, !i, page);
} }
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
sunxi_nfc_hw_ecc_enable(mtd); sunxi_nfc_hw_ecc_enable(mtd);
sunxi_nfc_randomizer_config(mtd, page, false); sunxi_nfc_randomizer_config(mtd, page, false);
sunxi_nfc_randomizer_enable(mtd); sunxi_nfc_randomizer_enable(mtd);
...@@ -1460,7 +1469,7 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd, ...@@ -1460,7 +1469,7 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
NULL, page); NULL, page);
return 0; return nand_prog_page_end_op(chip);
pio_fallback: pio_fallback:
return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page); return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page);
...@@ -1476,6 +1485,8 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd, ...@@ -1476,6 +1485,8 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
int ret, i, cur_off = 0; int ret, i, cur_off = 0;
bool raw_mode = false; bool raw_mode = false;
nand_read_page_op(chip, page, 0, NULL, 0);
sunxi_nfc_hw_ecc_enable(mtd); sunxi_nfc_hw_ecc_enable(mtd);
for (i = 0; i < ecc->steps; i++) { for (i = 0; i < ecc->steps; i++) {
...@@ -1512,6 +1523,8 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, ...@@ -1512,6 +1523,8 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
struct nand_ecc_ctrl *ecc = &chip->ecc; struct nand_ecc_ctrl *ecc = &chip->ecc;
int ret, i, cur_off = 0; int ret, i, cur_off = 0;
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
sunxi_nfc_hw_ecc_enable(mtd); sunxi_nfc_hw_ecc_enable(mtd);
for (i = 0; i < ecc->steps; i++) { for (i = 0; i < ecc->steps; i++) {
...@@ -1533,41 +1546,33 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, ...@@ -1533,41 +1546,33 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
sunxi_nfc_hw_ecc_disable(mtd); sunxi_nfc_hw_ecc_disable(mtd);
return 0; return nand_prog_page_end_op(chip);
} }
static int sunxi_nfc_hw_common_ecc_read_oob(struct mtd_info *mtd, static int sunxi_nfc_hw_common_ecc_read_oob(struct mtd_info *mtd,
struct nand_chip *chip, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
chip->pagebuf = -1; chip->pagebuf = -1;
return chip->ecc.read_page(mtd, chip, chip->buffers->databuf, 1, page); return chip->ecc.read_page(mtd, chip, chip->data_buf, 1, page);
} }
static int sunxi_nfc_hw_common_ecc_write_oob(struct mtd_info *mtd, static int sunxi_nfc_hw_common_ecc_write_oob(struct mtd_info *mtd,
struct nand_chip *chip, struct nand_chip *chip,
int page) int page)
{ {
int ret, status; int ret;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
chip->pagebuf = -1; chip->pagebuf = -1;
memset(chip->buffers->databuf, 0xff, mtd->writesize); memset(chip->data_buf, 0xff, mtd->writesize);
ret = chip->ecc.write_page(mtd, chip, chip->buffers->databuf, 1, page); ret = chip->ecc.write_page(mtd, chip, chip->data_buf, 1, page);
if (ret) if (ret)
return ret; return ret;
/* Send command to program the OOB data */ /* Send command to program the OOB data */
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
status = chip->waitfunc(mtd, chip);
return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
static const s32 tWB_lut[] = {6, 12, 16, 20}; static const s32 tWB_lut[] = {6, 12, 16, 20};
...@@ -1853,8 +1858,14 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, ...@@ -1853,8 +1858,14 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
/* Add ECC info retrieval from DT */ /* Add ECC info retrieval from DT */
for (i = 0; i < ARRAY_SIZE(strengths); i++) { for (i = 0; i < ARRAY_SIZE(strengths); i++) {
if (ecc->strength <= strengths[i]) if (ecc->strength <= strengths[i]) {
/*
* Update ecc->strength value with the actual strength
* that will be used by the ECC engine.
*/
ecc->strength = strengths[i];
break; break;
}
} }
if (i >= ARRAY_SIZE(strengths)) { if (i >= ARRAY_SIZE(strengths)) {
......
...@@ -329,7 +329,7 @@ static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos) ...@@ -329,7 +329,7 @@ static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
if (!*buf) { if (!*buf) {
/* skip over "len" bytes */ /* skip over "len" bytes */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, *pos, -1); nand_change_read_column_op(chip, *pos, NULL, 0, false);
} else { } else {
tango_read_buf(mtd, *buf, len); tango_read_buf(mtd, *buf, len);
*buf += len; *buf += len;
...@@ -344,7 +344,7 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos) ...@@ -344,7 +344,7 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
if (!*buf) { if (!*buf) {
/* skip over "len" bytes */ /* skip over "len" bytes */
chip->cmdfunc(mtd, NAND_CMD_RNDIN, *pos, -1); nand_change_write_column_op(chip, *pos, NULL, 0, false);
} else { } else {
tango_write_buf(mtd, *buf, len); tango_write_buf(mtd, *buf, len);
*buf += len; *buf += len;
...@@ -427,7 +427,7 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob) ...@@ -427,7 +427,7 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
u8 *buf, int oob_required, int page) u8 *buf, int oob_required, int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, buf, chip->oob_poi); raw_read(chip, buf, chip->oob_poi);
return 0; return 0;
} }
...@@ -435,23 +435,15 @@ static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -435,23 +435,15 @@ static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const u8 *buf, int oob_required, int page) const u8 *buf, int oob_required, int page)
{ {
int status; nand_prog_page_begin_op(chip, page, 0, NULL, 0);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
raw_write(chip, buf, chip->oob_poi); raw_write(chip, buf, chip->oob_poi);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
status = chip->waitfunc(mtd, chip);
if (status & NAND_STATUS_FAIL)
return -EIO;
return 0;
} }
static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, NULL, chip->oob_poi); raw_read(chip, NULL, chip->oob_poi);
return 0; return 0;
} }
...@@ -459,11 +451,9 @@ static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -459,11 +451,9 @@ static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip, static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page) int page)
{ {
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page); nand_prog_page_begin_op(chip, page, 0, NULL, 0);
raw_write(chip, NULL, chip->oob_poi); raw_write(chip, NULL, chip->oob_poi);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); return nand_prog_page_end_op(chip);
chip->waitfunc(mtd, chip);
return 0;
} }
static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res) static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res)
...@@ -590,7 +580,6 @@ static int chip_init(struct device *dev, struct device_node *np) ...@@ -590,7 +580,6 @@ static int chip_init(struct device *dev, struct device_node *np)
ecc->write_page = tango_write_page; ecc->write_page = tango_write_page;
ecc->read_oob = tango_read_oob; ecc->read_oob = tango_read_oob;
ecc->write_oob = tango_write_oob; ecc->write_oob = tango_write_oob;
ecc->options = NAND_ECC_CUSTOM_PAGE_ACCESS;
err = nand_scan_tail(mtd); err = nand_scan_tail(mtd);
if (err) if (err)
......
...@@ -192,6 +192,7 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip) ...@@ -192,6 +192,7 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
{ {
struct tmio_nand *tmio = mtd_to_tmio(mtd); struct tmio_nand *tmio = mtd_to_tmio(mtd);
long timeout; long timeout;
u8 status;
/* enable RDYREQ interrupt */ /* enable RDYREQ interrupt */
tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
...@@ -212,8 +213,8 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip) ...@@ -212,8 +213,8 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n"); dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n");
} }
nand_chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); nand_status_op(nand_chip, &status);
return nand_chip->read_byte(mtd); return status;
} }
/* /*
......
...@@ -560,7 +560,7 @@ static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -560,7 +560,7 @@ static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
int eccsize = chip->ecc.size; int eccsize = chip->ecc.size;
int stat; int stat;
vf610_nfc_read_buf(mtd, buf, eccsize); nand_read_page_op(chip, page, 0, buf, eccsize);
if (oob_required) if (oob_required)
vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize); vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
...@@ -580,7 +580,7 @@ static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -580,7 +580,7 @@ static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
{ {
struct vf610_nfc *nfc = mtd_to_nfc(mtd); struct vf610_nfc *nfc = mtd_to_nfc(mtd);
vf610_nfc_write_buf(mtd, buf, mtd->writesize); nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
if (oob_required) if (oob_required)
vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize); vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
...@@ -588,7 +588,7 @@ static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -588,7 +588,7 @@ static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
nfc->use_hw_ecc = true; nfc->use_hw_ecc = true;
nfc->write_sz = mtd->writesize + mtd->oobsize; nfc->write_sz = mtd->writesize + mtd->oobsize;
return 0; return nand_prog_page_end_op(chip);
} }
static const struct of_device_id vf610_nfc_dt_ids[] = { static const struct of_device_id vf610_nfc_dt_ids[] = {
......
...@@ -4,8 +4,7 @@ menuconfig MTD_ONENAND ...@@ -4,8 +4,7 @@ menuconfig MTD_ONENAND
depends on HAS_IOMEM depends on HAS_IOMEM
help help
This enables support for accessing all type of OneNAND flash This enables support for accessing all type of OneNAND flash
devices. For further information see devices.
<http://www.samsung.com/Products/Semiconductor/OneNAND/index.htm>
if MTD_ONENAND if MTD_ONENAND
...@@ -26,9 +25,11 @@ config MTD_ONENAND_GENERIC ...@@ -26,9 +25,11 @@ config MTD_ONENAND_GENERIC
config MTD_ONENAND_OMAP2 config MTD_ONENAND_OMAP2
tristate "OneNAND on OMAP2/OMAP3 support" tristate "OneNAND on OMAP2/OMAP3 support"
depends on ARCH_OMAP2 || ARCH_OMAP3 depends on ARCH_OMAP2 || ARCH_OMAP3
depends on OF || COMPILE_TEST
help help
Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU Support for a OneNAND flash device connected to an OMAP2/OMAP3 SoC
via the GPMC memory controller. via the GPMC memory controller.
Enable dmaengine and gpiolib for better performance.
config MTD_ONENAND_SAMSUNG config MTD_ONENAND_SAMSUNG
tristate "OneNAND on Samsung SOC controller support" tristate "OneNAND on Samsung SOC controller support"
......
此差异已折叠。
...@@ -1383,15 +1383,6 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, ...@@ -1383,15 +1383,6 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
return -EINVAL; return -EINVAL;
} }
/* Do not allow reads past end of device */
if (unlikely(from >= mtd->size ||
column + len > ((mtd->size >> this->page_shift) -
(from >> this->page_shift)) * oobsize)) {
printk(KERN_ERR "%s: Attempted to read beyond end of device\n",
__func__);
return -EINVAL;
}
stats = mtd->ecc_stats; stats = mtd->ecc_stats;
readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
...@@ -1447,38 +1438,6 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, ...@@ -1447,38 +1438,6 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
return 0; return 0;
} }
/**
* onenand_read - [MTD Interface] Read data from flash
* @param mtd MTD device structure
* @param from offset to read from
* @param len number of bytes to read
* @param retlen pointer to variable to store the number of read bytes
* @param buf the databuffer to put data
*
* Read with ecc
*/
static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct onenand_chip *this = mtd->priv;
struct mtd_oob_ops ops = {
.len = len,
.ooblen = 0,
.datbuf = buf,
.oobbuf = NULL,
};
int ret;
onenand_get_device(mtd, FL_READING);
ret = ONENAND_IS_4KB_PAGE(this) ?
onenand_mlc_read_ops_nolock(mtd, from, &ops) :
onenand_read_ops_nolock(mtd, from, &ops);
onenand_release_device(mtd);
*retlen = ops.retlen;
return ret;
}
/** /**
* onenand_read_oob - [MTD Interface] Read main and/or out-of-band * onenand_read_oob - [MTD Interface] Read main and/or out-of-band
* @param mtd: MTD device structure * @param mtd: MTD device structure
...@@ -2056,15 +2015,6 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, ...@@ -2056,15 +2015,6 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
return -EINVAL; return -EINVAL;
} }
/* Do not allow reads past end of device */
if (unlikely(to >= mtd->size ||
column + len > ((mtd->size >> this->page_shift) -
(to >> this->page_shift)) * oobsize)) {
printk(KERN_ERR "%s: Attempted to write past end of device\n",
__func__);
return -EINVAL;
}
oobbuf = this->oob_buf; oobbuf = this->oob_buf;
oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB; oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
...@@ -2128,35 +2078,6 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, ...@@ -2128,35 +2078,6 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
return ret; return ret;
} }
/**
* onenand_write - [MTD Interface] write buffer to FLASH
* @param mtd MTD device structure
* @param to offset to write to
* @param len number of bytes to write
* @param retlen pointer to variable to store the number of written bytes
* @param buf the data to write
*
* Write with ECC
*/
static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
struct mtd_oob_ops ops = {
.len = len,
.ooblen = 0,
.datbuf = (u_char *) buf,
.oobbuf = NULL,
};
int ret;
onenand_get_device(mtd, FL_WRITING);
ret = onenand_write_ops_nolock(mtd, to, &ops);
onenand_release_device(mtd);
*retlen = ops.retlen;
return ret;
}
/** /**
* onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band
* @param mtd: MTD device structure * @param mtd: MTD device structure
...@@ -4038,8 +3959,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) ...@@ -4038,8 +3959,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
mtd->_erase = onenand_erase; mtd->_erase = onenand_erase;
mtd->_point = NULL; mtd->_point = NULL;
mtd->_unpoint = NULL; mtd->_unpoint = NULL;
mtd->_read = onenand_read;
mtd->_write = onenand_write;
mtd->_read_oob = onenand_read_oob; mtd->_read_oob = onenand_read_oob;
mtd->_write_oob = onenand_write_oob; mtd->_write_oob = onenand_write_oob;
mtd->_panic_write = onenand_panic_write; mtd->_panic_write = onenand_panic_write;
......
此差异已折叠。
...@@ -192,7 +192,7 @@ static int sharpsl_nand_init_ftl(struct mtd_info *mtd, struct sharpsl_ftl *ftl) ...@@ -192,7 +192,7 @@ static int sharpsl_nand_init_ftl(struct mtd_info *mtd, struct sharpsl_ftl *ftl)
/* create physical-logical table */ /* create physical-logical table */
for (block_num = 0; block_num < phymax; block_num++) { for (block_num = 0; block_num < phymax; block_num++) {
block_adr = block_num * mtd->erasesize; block_adr = (loff_t)block_num * mtd->erasesize;
if (mtd_block_isbad(mtd, block_adr)) if (mtd_block_isbad(mtd, block_adr))
continue; continue;
...@@ -219,7 +219,7 @@ static int sharpsl_nand_init_ftl(struct mtd_info *mtd, struct sharpsl_ftl *ftl) ...@@ -219,7 +219,7 @@ static int sharpsl_nand_init_ftl(struct mtd_info *mtd, struct sharpsl_ftl *ftl)
return ret; return ret;
} }
void sharpsl_nand_cleanup_ftl(struct sharpsl_ftl *ftl) static void sharpsl_nand_cleanup_ftl(struct sharpsl_ftl *ftl)
{ {
kfree(ftl->log2phy); kfree(ftl->log2phy);
} }
...@@ -244,7 +244,7 @@ static int sharpsl_nand_read_laddr(struct mtd_info *mtd, ...@@ -244,7 +244,7 @@ static int sharpsl_nand_read_laddr(struct mtd_info *mtd,
return -EINVAL; return -EINVAL;
block_num = ftl->log2phy[log_num]; block_num = ftl->log2phy[log_num];
block_adr = block_num * mtd->erasesize; block_adr = (loff_t)block_num * mtd->erasesize;
block_ofs = mtd_mod_by_eb((u32)from, mtd); block_ofs = mtd_mod_by_eb((u32)from, mtd);
err = mtd_read(mtd, block_adr + block_ofs, len, &retlen, buf); err = mtd_read(mtd, block_adr + block_ofs, len, &retlen, buf);
......
...@@ -801,10 +801,10 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q) ...@@ -801,10 +801,10 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
} }
static const struct of_device_id fsl_qspi_dt_ids[] = { static const struct of_device_id fsl_qspi_dt_ids[] = {
{ .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, }, { .compatible = "fsl,vf610-qspi", .data = &vybrid_data, },
{ .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, }, { .compatible = "fsl,imx6sx-qspi", .data = &imx6sx_data, },
{ .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, }, { .compatible = "fsl,imx7d-qspi", .data = &imx7d_data, },
{ .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, }, { .compatible = "fsl,imx6ul-qspi", .data = &imx6ul_data, },
{ .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, }, { .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, },
{ /* sentinel */ } { /* sentinel */ }
}; };
......
...@@ -138,7 +138,6 @@ ...@@ -138,7 +138,6 @@
* @erase_64k: 64k erase supported * @erase_64k: 64k erase supported
* @opcodes: Opcodes which are supported. This are programmed by BIOS * @opcodes: Opcodes which are supported. This are programmed by BIOS
* before it locks down the controller. * before it locks down the controller.
* @preopcodes: Preopcodes which are supported.
*/ */
struct intel_spi { struct intel_spi {
struct device *dev; struct device *dev;
...@@ -155,7 +154,6 @@ struct intel_spi { ...@@ -155,7 +154,6 @@ struct intel_spi {
bool swseq_erase; bool swseq_erase;
bool erase_64k; bool erase_64k;
u8 opcodes[8]; u8 opcodes[8];
u8 preopcodes[2];
}; };
static bool writeable; static bool writeable;
...@@ -400,10 +398,6 @@ static int intel_spi_init(struct intel_spi *ispi) ...@@ -400,10 +398,6 @@ static int intel_spi_init(struct intel_spi *ispi)
ispi->opcodes[i] = opmenu0 >> i * 8; ispi->opcodes[i] = opmenu0 >> i * 8;
ispi->opcodes[i + 4] = opmenu1 >> i * 8; ispi->opcodes[i + 4] = opmenu1 >> i * 8;
} }
val = readl(ispi->sregs + PREOP_OPTYPE);
ispi->preopcodes[0] = val;
ispi->preopcodes[1] = val >> 8;
} }
} }
......
此差异已折叠。
此差异已折叠。
...@@ -151,7 +151,7 @@ static int read_page(int log) ...@@ -151,7 +151,7 @@ static int read_page(int log)
memcpy(&oldstats, &mtd->ecc_stats, sizeof(oldstats)); memcpy(&oldstats, &mtd->ecc_stats, sizeof(oldstats));
err = mtd_read(mtd, offset, mtd->writesize, &read, rbuffer); err = mtd_read(mtd, offset, mtd->writesize, &read, rbuffer);
if (err == -EUCLEAN) if (!err || err == -EUCLEAN)
err = mtd->ecc_stats.corrected - oldstats.corrected; err = mtd->ecc_stats.corrected - oldstats.corrected;
if (err < 0 || read != mtd->writesize) { if (err < 0 || read != mtd->writesize) {
......
此差异已折叠。
...@@ -637,8 +637,7 @@ static int spinand_write_page_hwecc(struct mtd_info *mtd, ...@@ -637,8 +637,7 @@ static int spinand_write_page_hwecc(struct mtd_info *mtd,
int eccsteps = chip->ecc.steps; int eccsteps = chip->ecc.steps;
enable_hw_ecc = 1; enable_hw_ecc = 1;
chip->write_buf(mtd, p, eccsize * eccsteps); return nand_prog_page_op(chip, page, 0, p, eccsize * eccsteps);
return 0;
} }
static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
...@@ -653,7 +652,7 @@ static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -653,7 +652,7 @@ static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
enable_read_hw_ecc = 1; enable_read_hw_ecc = 1;
chip->read_buf(mtd, p, eccsize * eccsteps); nand_read_page_op(chip, page, 0, p, eccsize * eccsteps);
if (oob_required) if (oob_required)
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
......
此差异已折叠。
...@@ -489,6 +489,34 @@ static inline uint32_t mtd_mod_by_eb(uint64_t sz, struct mtd_info *mtd) ...@@ -489,6 +489,34 @@ static inline uint32_t mtd_mod_by_eb(uint64_t sz, struct mtd_info *mtd)
return do_div(sz, mtd->erasesize); return do_div(sz, mtd->erasesize);
} }
/**
* mtd_align_erase_req - Adjust an erase request to align things on eraseblock
* boundaries.
* @mtd: the MTD device this erase request applies on
* @req: the erase request to adjust
*
* This function will adjust @req->addr and @req->len to align them on
* @mtd->erasesize. Of course we expect @mtd->erasesize to be != 0.
*/
static inline void mtd_align_erase_req(struct mtd_info *mtd,
struct erase_info *req)
{
u32 mod;
if (WARN_ON(!mtd->erasesize))
return;
mod = mtd_mod_by_eb(req->addr, mtd);
if (mod) {
req->addr -= mod;
req->len += mod;
}
mod = mtd_mod_by_eb(req->addr + req->len, mtd);
if (mod)
req->len += mtd->erasesize - mod;
}
static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
{ {
if (mtd->writesize_shift) if (mtd->writesize_shift)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册