SPI NOR changes:
Core changes: * Support non-uniform erase size * Support controllers with limited TX fifo size Driver changes: * m25p80: Re-issue a WREN command after each write access * cadence: Pass a proper dir value to dma_[un]map_single() * fsl-qspi: Check fsl_qspi_get_seqid() return val make sure 4B addressing opcodes are properly handled * intel-spi: Add a new PCI entry for Ice Lake NAND changes: Raw NAND core changes: - Two batchs of cleanups of the NAND API, including: * Deprecating a lot of interfaces (now replaced by ->exec_op()). * Moving code in separate drivers (JEDEC, ONFI), in private files (internals), in platform drivers, etc. * Functions/structures reordering. * Exclusive use of the nand_chip structure instead of the MTD one all across the subsystem. - Addition of the nand_wait_readrdy/rdy_op() helpers. Raw NAND controllers drivers changes: - Various coccinelle patches. - Marvell: * Use regmap_update_bits() for syscon access. * More documentation. * BCH failure path rework. * More layouts to be supported. * IRQ handler complete() condition fixed. - Fsl_ifc: * SRAM initialization fixed for newer controller versions. - Denali: * Fix licenses mismatch and use a SPDX tag. * Set SPARE_AREA_SKIP_BYTES register to 8 if unset. - Qualcomm: * Do not include dma-direct.h. - Docg4: * Removed. - Ams-delta: * Use of a GPIO lookup table * Internal machinery changes. Raw NAND chip drivers changes: - Toshiba: * Add support for Toshiba memory BENAND * Pass a single nand_chip object to the status helper. - ESMT: * New driver to retrieve the ECC requirements from the 5th ID byte. MTD changes: * physmap cleanups/fixe * gpio-addr-flash cleanups/fixes -----BEGIN PGP SIGNATURE----- iQJQBAABCgA6FiEEKmCqpbOU668PNA69Ze02AX4ItwAFAlvNmJocHGJvcmlzLmJy ZXppbGxvbkBib290bGluLmNvbQAKCRBl7TYBfgi3AKr+D/4pH0gYSGDUstZsqUHW gZsPRU4jmOA+OCRbSxE03bOZOYR0UPgdoUYLfAKhZ5qxc7wHd3b47wykP0kUEviu lC8QhSs4DUA+EuMVPDVS4FlXRT0e3dMV7jh/IK6nInshD2YkaovyCqa6GvgwFEcM 7BCizxRhtHV8+fo7GVQWuMLb9ZfbEvz42D0sYOu6hIsF1SnRDvHOvfdDUFEXpJoF a2mC9ove65ChEzc2iZ/r260iZ4aoJYb9XJRJKWxmYeITZSmLNmcrUyGqAaNQ7NRc AIuPXASbeHGjrIuEfXpKYW07AE5MV1nJFSk3v4u5FjgoohOoobPp7npk+Lz/qwe3 y8/uW9qOQ/iEOsRnkvMGNu4Yjhw41L1a+J5wVvUvzmwHy1xMCrRHYB/8gXoZzemR A7XmCPwjAFVWv1WeKV2cs5MLW9yZq9QNMtGLlNs5OgFR6CccLk67/tHIkYLsJ/l9 IDXFhd/YKhTeF361u6Iimmgb427TwM71P9N+OMpv4nk46DxurpxkgGle3nslzKNU DOFNFlMGiPIx3h4X96AKER6u7cxiOXnLGq+XeHa/y8tIrziy3jg03YoTh0RSwKxV J3EXwh1sFLaeebwWEgpE3Ag1LOxpRCqJ2ED71SPzS/DR/938HBVsEoPqUEHNf1in jwsUB3cRzNwf+XX68DRCVT5GFA== =7w4w -----END PGP SIGNATURE----- Merge tag 'mtd/for-4.20' of git://git.infradead.org/linux-mtd Pull mtd updates from Boris Brezillon: "SPI NOR core changes: - Support non-uniform erase size - Support controllers with limited TX fifo size Driver changes: - m25p80: Re-issue a WREN command after each write access - cadence: Pass a proper dir value to dma_[un]map_single() - fsl-qspi: Check fsl_qspi_get_seqid() return val make sure 4B addressing opcodes are properly handled - intel-spi: Add a new PCI entry for Ice Lake Raw NAND core changes: - Two batchs of cleanups of the NAND API, including: * Deprecating a lot of interfaces (now replaced by ->exec_op()). * Moving code in separate drivers (JEDEC, ONFI), in private files (internals), in platform drivers, etc. * Functions/structures reordering. * Exclusive use of the nand_chip structure instead of the MTD one all across the subsystem. - Addition of the nand_wait_readrdy/rdy_op() helpers. Raw NAND controllers drivers changes: - Various coccinelle patches. - Marvell: * Use regmap_update_bits() for syscon access. * More documentation. * BCH failure path rework. * More layouts to be supported. * IRQ handler complete() condition fixed. - Fsl_ifc: * SRAM initialization fixed for newer controller versions. - Denali: * Fix licenses mismatch and use a SPDX tag. * Set SPARE_AREA_SKIP_BYTES register to 8 if unset. - Qualcomm: * Do not include dma-direct.h. - Docg4: * Removed. - Ams-delta: * Use of a GPIO lookup table * Internal machinery changes. Raw NAND chip drivers changes: - Toshiba: * Add support for Toshiba memory BENAND * Pass a single nand_chip object to the status helper. - ESMT: * New driver to retrieve the ECC requirements from the 5th ID byte. MTD changes: - physmap cleanups/fixe - gpio-addr-flash cleanups/fixes" * tag 'mtd/for-4.20' of git://git.infradead.org/linux-mtd: (93 commits) jffs2: free jffs2_sb_info through jffs2_kill_sb() mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB mtd: spi-nor: intel-spi: Add support for Intel Ice Lake SPI serial flash mtd: maps: gpio-addr-flash: Convert to gpiod mtd: maps: gpio-addr-flash: Replace array with an integer mtd: maps: gpio-addr-flash: Use order instead of size mtd: spi-nor: fsl-quadspi: Don't let -EINVAL on the bus mtd: devices: m25p80: Make sure WRITE_EN is issued before each write mtd: spi-nor: Support controllers with limited TX FIFO size mtd: spi-nor: cadence-quadspi: Use proper enum for dma_[un]map_single mtd: spi-nor: parse SFDP Sector Map Parameter Table mtd: spi-nor: add support to non-uniform SFDP SPI NOR flash memories mtd: rawnand: marvell: fix the IRQ handler complete() condition mtd: rawnand: denali: set SPARE_AREA_SKIP_BYTES register to 8 if unset mtd: rawnand: r852: fix spelling mistake "card_registred" -> "card_registered" mtd: rawnand: toshiba: Pass a single nand_chip object to the status helper mtd: maps: gpio-addr-flash: Use devm_* functions mtd: maps: gpio-addr-flash: Fix ioremapped size mtd: maps: gpio-addr-flash: Replace custom printk mtd: physmap_of: Release resources on error ...
This commit is contained in:
commit
a36cf68651
|
@ -180,10 +180,10 @@ by a chip select decoder.
|
|||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
switch(cmd){
|
||||
case NAND_CTL_SETCLE: this->IO_ADDR_W |= CLE_ADRR_BIT; break;
|
||||
case NAND_CTL_CLRCLE: this->IO_ADDR_W &= ~CLE_ADRR_BIT; break;
|
||||
case NAND_CTL_SETALE: this->IO_ADDR_W |= ALE_ADRR_BIT; break;
|
||||
case NAND_CTL_CLRALE: this->IO_ADDR_W &= ~ALE_ADRR_BIT; break;
|
||||
case NAND_CTL_SETCLE: this->legacy.IO_ADDR_W |= CLE_ADRR_BIT; break;
|
||||
case NAND_CTL_CLRCLE: this->legacy.IO_ADDR_W &= ~CLE_ADRR_BIT; break;
|
||||
case NAND_CTL_SETALE: this->legacy.IO_ADDR_W |= ALE_ADRR_BIT; break;
|
||||
case NAND_CTL_CLRALE: this->legacy.IO_ADDR_W &= ~ALE_ADRR_BIT; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,7 @@ to read back the state of the pin. The function has no arguments and
|
|||
should return 0, if the device is busy (R/B pin is low) and 1, if the
|
||||
device is ready (R/B pin is high). If the hardware interface does not
|
||||
give access to the ready busy pin, then the function must not be defined
|
||||
and the function pointer this->dev_ready is set to NULL.
|
||||
and the function pointer this->legacy.dev_ready is set to NULL.
|
||||
|
||||
Init function
|
||||
-------------
|
||||
|
@ -235,18 +235,18 @@ necessary information about the device.
|
|||
}
|
||||
|
||||
/* Set address of NAND IO lines */
|
||||
this->IO_ADDR_R = baseaddr;
|
||||
this->IO_ADDR_W = baseaddr;
|
||||
this->legacy.IO_ADDR_R = baseaddr;
|
||||
this->legacy.IO_ADDR_W = baseaddr;
|
||||
/* Reference hardware control function */
|
||||
this->hwcontrol = board_hwcontrol;
|
||||
/* Set command delay time, see datasheet for correct value */
|
||||
this->chip_delay = CHIP_DEPENDEND_COMMAND_DELAY;
|
||||
this->legacy.chip_delay = CHIP_DEPENDEND_COMMAND_DELAY;
|
||||
/* Assign the device ready function, if available */
|
||||
this->dev_ready = board_dev_ready;
|
||||
this->legacy.dev_ready = board_dev_ready;
|
||||
this->eccmode = NAND_ECC_SOFT;
|
||||
|
||||
/* Scan to find existence of the device */
|
||||
if (nand_scan (board_mtd, 1)) {
|
||||
if (nand_scan (this, 1)) {
|
||||
err = -ENXIO;
|
||||
goto out_ior;
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ unregisters the partitions in the MTD layer.
|
|||
static void __exit board_cleanup (void)
|
||||
{
|
||||
/* Release resources, unregister device */
|
||||
nand_release (board_mtd);
|
||||
nand_release (mtd_to_nand(board_mtd));
|
||||
|
||||
/* unmap physical address */
|
||||
iounmap(baseaddr);
|
||||
|
@ -336,17 +336,17 @@ connected to an address decoder.
|
|||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
/* Deselect all chips */
|
||||
this->IO_ADDR_R &= ~BOARD_NAND_ADDR_MASK;
|
||||
this->IO_ADDR_W &= ~BOARD_NAND_ADDR_MASK;
|
||||
this->legacy.IO_ADDR_R &= ~BOARD_NAND_ADDR_MASK;
|
||||
this->legacy.IO_ADDR_W &= ~BOARD_NAND_ADDR_MASK;
|
||||
switch (chip) {
|
||||
case 0:
|
||||
this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIP0;
|
||||
this->IO_ADDR_W |= BOARD_NAND_ADDR_CHIP0;
|
||||
this->legacy.IO_ADDR_R |= BOARD_NAND_ADDR_CHIP0;
|
||||
this->legacy.IO_ADDR_W |= BOARD_NAND_ADDR_CHIP0;
|
||||
break;
|
||||
....
|
||||
case n:
|
||||
this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIPn;
|
||||
this->IO_ADDR_W |= BOARD_NAND_ADDR_CHIPn;
|
||||
this->legacy.IO_ADDR_R |= BOARD_NAND_ADDR_CHIPn;
|
||||
this->legacy.IO_ADDR_W |= BOARD_NAND_ADDR_CHIPn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
|
||||
About this document
|
||||
===================
|
||||
|
||||
Some notes about Marvell's NAND controller available in PXA and Armada 370/XP
|
||||
SoC (aka NFCv1 and NFCv2), with an emphasis on the latter.
|
||||
|
||||
NFCv2 controller background
|
||||
===========================
|
||||
|
||||
The controller has a 2176 bytes FIFO buffer. Therefore, in order to support
|
||||
larger pages, I/O operations on 4 KiB and 8 KiB pages is done with a set of
|
||||
chunked transfers.
|
||||
|
||||
For instance, if we choose a 2048 data chunk and set "BCH" ECC (see below)
|
||||
we'll have this layout in the pages:
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
| 2048B data | 32B spare | 30B ECC || 2048B data | 32B spare | 30B ECC | ... |
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
The driver reads the data and spare portions independently and builds an internal
|
||||
buffer with this layout (in the 4 KiB page case):
|
||||
|
||||
------------------------------------------
|
||||
| 4096B data | 64B spare |
|
||||
------------------------------------------
|
||||
|
||||
Also, for the READOOB command the driver disables the ECC and reads a 'spare + ECC'
|
||||
OOB, one per chunk read.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
| 4096B data | 32B spare | 30B ECC | 32B spare | 30B ECC |
|
||||
-------------------------------------------------------------------
|
||||
|
||||
So, in order to achieve reading (for instance), we issue several READ0 commands
|
||||
(with some additional controller-specific magic) and read two chunks of 2080B
|
||||
(2048 data + 32 spare) each.
|
||||
The driver accommodates this data to expose the NAND core a contiguous buffer
|
||||
(4096 data + spare) or (4096 + spare + ECC + spare + ECC).
|
||||
|
||||
ECC
|
||||
===
|
||||
|
||||
The controller has built-in hardware ECC capabilities. In addition it is
|
||||
configurable between two modes: 1) Hamming, 2) BCH.
|
||||
|
||||
Note that the actual BCH mode: BCH-4 or BCH-8 will depend on the way
|
||||
the controller is configured to transfer the data.
|
||||
|
||||
In the BCH mode the ECC code will be calculated for each transferred chunk
|
||||
and expected to be located (when reading/programming) right after the spare
|
||||
bytes as the figure above shows.
|
||||
|
||||
So, repeating the above scheme, a 2048B data chunk will be followed by 32B
|
||||
spare, and then the ECC controller will read/write the ECC code (30B in
|
||||
this case):
|
||||
|
||||
------------------------------------
|
||||
| 2048B data | 32B spare | 30B ECC |
|
||||
------------------------------------
|
||||
|
||||
If the ECC mode is 'BCH' then the ECC is *always* 30 bytes long.
|
||||
If the ECC mode is 'Hamming' the ECC is 6 bytes long, for each 512B block.
|
||||
So in Hamming mode, a 2048B page will have a 24B ECC.
|
||||
|
||||
Despite all of the above, the controller requires the driver to only read or
|
||||
write in multiples of 8-bytes, because the data buffer is 64-bits.
|
||||
|
||||
OOB
|
||||
===
|
||||
|
||||
Because of the above scheme, and because the "spare" OOB is really located in
|
||||
the middle of a page, spare OOB cannot be read or write independently of the
|
||||
data area. In other words, in order to read the OOB (aka READOOB), the entire
|
||||
page (aka READ0) has to be read.
|
||||
|
||||
In the same sense, in order to write to the spare OOB the driver has to write
|
||||
an *entire* page.
|
||||
|
||||
Factory bad blocks handling
|
||||
===========================
|
||||
|
||||
Given the ECC BCH requires to layout the device's pages in a split
|
||||
data/OOB/data/OOB way, the controller has a view of the flash page that's
|
||||
different from the specified (aka the manufacturer's) view. In other words,
|
||||
|
||||
Factory view:
|
||||
|
||||
-----------------------------------------------
|
||||
| Data |x OOB |
|
||||
-----------------------------------------------
|
||||
|
||||
Driver's view:
|
||||
|
||||
-----------------------------------------------
|
||||
| Data | OOB | Data x | OOB |
|
||||
-----------------------------------------------
|
||||
|
||||
It can be seen from the above, that the factory bad block marker must be
|
||||
searched within the 'data' region, and not in the usual OOB region.
|
||||
|
||||
In addition, this means under regular usage the driver will write such
|
||||
position (since it belongs to the data region) and every used block is
|
||||
likely to be marked as bad.
|
||||
|
||||
For this reason, marking the block as bad in the OOB is explicitly
|
||||
disabled by using the NAND_BBT_NO_OOB_BBM option in the driver. The rationale
|
||||
for this is that there's no point in marking a block as bad, because good
|
||||
blocks are also 'marked as bad' (in the OOB BBM sense) under normal usage.
|
||||
|
||||
Instead, the driver relies on the bad block table alone, and should only perform
|
||||
the bad block scan on the very first time (when the device hasn't been used).
|
|
@ -23,8 +23,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <linux/platform_data/video-ep93xx.h>
|
||||
|
@ -43,12 +42,11 @@
|
|||
#define SNAPPERCL15_NAND_CEN (1 << 11) /* Chip enable (active low) */
|
||||
#define SNAPPERCL15_NAND_RDY (1 << 14) /* Device ready */
|
||||
|
||||
#define NAND_CTRL_ADDR(chip) (chip->IO_ADDR_W + 0x40)
|
||||
#define NAND_CTRL_ADDR(chip) (chip->legacy.IO_ADDR_W + 0x40)
|
||||
|
||||
static void snappercl15_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
static void snappercl15_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
static u16 nand_state = SNAPPERCL15_NAND_WPN;
|
||||
u16 set;
|
||||
|
||||
|
@ -70,13 +68,12 @@ static void snappercl15_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
|||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
__raw_writew((cmd & 0xff) | nand_state, chip->IO_ADDR_W);
|
||||
__raw_writew((cmd & 0xff) | nand_state,
|
||||
chip->legacy.IO_ADDR_W);
|
||||
}
|
||||
|
||||
static int snappercl15_nand_dev_ready(struct mtd_info *mtd)
|
||||
static int snappercl15_nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
return !!(__raw_readw(NAND_CTRL_ADDR(chip)) & SNAPPERCL15_NAND_RDY);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/spi/mmc_spi.h>
|
||||
|
@ -76,13 +75,11 @@ static void __init ts72xx_map_io(void)
|
|||
#define TS72XX_NAND_CONTROL_ADDR_LINE 22 /* 0xN0400000 */
|
||||
#define TS72XX_NAND_BUSY_ADDR_LINE 23 /* 0xN0800000 */
|
||||
|
||||
static void ts72xx_nand_hwcontrol(struct mtd_info *mtd,
|
||||
static void ts72xx_nand_hwcontrol(struct nand_chip *chip,
|
||||
int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
void __iomem *addr = chip->IO_ADDR_R;
|
||||
void __iomem *addr = chip->legacy.IO_ADDR_R;
|
||||
unsigned char bits;
|
||||
|
||||
addr += (1 << TS72XX_NAND_CONTROL_ADDR_LINE);
|
||||
|
@ -96,13 +93,12 @@ static void ts72xx_nand_hwcontrol(struct mtd_info *mtd,
|
|||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
__raw_writeb(cmd, chip->IO_ADDR_W);
|
||||
__raw_writeb(cmd, chip->legacy.IO_ADDR_W);
|
||||
}
|
||||
|
||||
static int ts72xx_nand_device_ready(struct mtd_info *mtd)
|
||||
static int ts72xx_nand_device_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
void __iomem *addr = chip->IO_ADDR_R;
|
||||
void __iomem *addr = chip->legacy.IO_ADDR_R;
|
||||
|
||||
addr += (1 << TS72XX_NAND_BUSY_ADDR_LINE);
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <linux/memory.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
|
@ -129,30 +129,29 @@ static void qong_init_nor_mtd(void)
|
|||
/*
|
||||
* Hardware specific access to control-lines
|
||||
*/
|
||||
static void qong_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
static void qong_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
return;
|
||||
|
||||
if (ctrl & NAND_CLE)
|
||||
writeb(cmd, nand_chip->IO_ADDR_W + (1 << 24));
|
||||
writeb(cmd, nand_chip->legacy.IO_ADDR_W + (1 << 24));
|
||||
else
|
||||
writeb(cmd, nand_chip->IO_ADDR_W + (1 << 23));
|
||||
writeb(cmd, nand_chip->legacy.IO_ADDR_W + (1 << 23));
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the Device Ready pin.
|
||||
*/
|
||||
static int qong_nand_device_ready(struct mtd_info *mtd)
|
||||
static int qong_nand_device_ready(struct nand_chip *chip)
|
||||
{
|
||||
return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_NFRB));
|
||||
}
|
||||
|
||||
static void qong_nand_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void qong_nand_select_chip(struct nand_chip *chip, int cs)
|
||||
{
|
||||
if (chip >= 0)
|
||||
if (cs >= 0)
|
||||
gpio_set_value(IOMUX_TO_GPIO(MX31_PIN_NFCE_B), 0);
|
||||
else
|
||||
gpio_set_value(IOMUX_TO_GPIO(MX31_PIN_NFCE_B), 1);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <asm/types.h>
|
||||
|
@ -75,9 +76,8 @@ static struct mtd_partition ixdp425_partitions[] = {
|
|||
};
|
||||
|
||||
static void
|
||||
ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
ixdp425_flash_nand_cmd_ctrl(struct nand_chip *this, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int offset = (int)nand_get_controller_data(this);
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
|
@ -93,7 +93,7 @@ ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
|||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
writeb(cmd, this->IO_ADDR_W + offset);
|
||||
writeb(cmd, this->legacy.IO_ADDR_W + offset);
|
||||
}
|
||||
|
||||
static struct platform_nand_data ixdp425_flash_nand_data = {
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/smc91x.h>
|
||||
|
@ -186,7 +185,7 @@ static struct platform_device nor_device = {
|
|||
|
||||
#define FSAMPLE_NAND_RB_GPIO_PIN 62
|
||||
|
||||
static int nand_dev_ready(struct mtd_info *mtd)
|
||||
static int nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
return gpio_get_value(FSAMPLE_NAND_RB_GPIO_PIN);
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/mfd/tps65010.h>
|
||||
|
@ -182,7 +181,7 @@ static struct mtd_partition h2_nand_partitions[] = {
|
|||
|
||||
#define H2_NAND_RB_GPIO_PIN 62
|
||||
|
||||
static int h2_nand_dev_ready(struct mtd_info *mtd)
|
||||
static int h2_nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
return gpio_get_value(H2_NAND_RB_GPIO_PIN);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <linux/workqueue.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/input.h>
|
||||
|
@ -185,7 +185,7 @@ static struct mtd_partition nand_partitions[] = {
|
|||
|
||||
#define H3_NAND_RB_GPIO_PIN 10
|
||||
|
||||
static int nand_dev_ready(struct mtd_info *mtd)
|
||||
static int nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
return gpio_get_value(H3_NAND_RB_GPIO_PIN);
|
||||
}
|
||||
|
|
|
@ -20,9 +20,8 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
void omap1_nand_cmd_ctl(struct nand_chip *this, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
unsigned long mask;
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
|
@ -32,6 +31,6 @@ void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
|||
if (ctrl & NAND_ALE)
|
||||
mask |= 0x04;
|
||||
|
||||
writeb(cmd, this->IO_ADDR_W + mask);
|
||||
writeb(cmd, this->legacy.IO_ADDR_W + mask);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/smc91x.h>
|
||||
|
@ -144,7 +143,7 @@ static struct platform_device nor_device = {
|
|||
|
||||
#define P2_NAND_RB_GPIO_PIN 62
|
||||
|
||||
static int nand_dev_ready(struct mtd_info *mtd)
|
||||
static int nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
return gpio_get_value(P2_NAND_RB_GPIO_PIN);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#ifndef __ARCH_ARM_MACH_OMAP1_COMMON_H
|
||||
#define __ARCH_ARM_MACH_OMAP1_COMMON_H
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/platform_data/i2c-omap.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
|
@ -82,7 +81,8 @@ void omap1_restart(enum reboot_mode, const char *);
|
|||
|
||||
extern void __init omap_check_revision(void);
|
||||
|
||||
extern void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd,
|
||||
struct nand_chip;
|
||||
extern void omap1_nand_cmd_ctl(struct nand_chip *this, int cmd,
|
||||
unsigned int ctrl);
|
||||
|
||||
extern void omap1_timer_init(void);
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/mv643xx_eth.h>
|
||||
#include <linux/ata_platform.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/timeriomem-rng.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
@ -131,11 +130,9 @@ static void ts78xx_ts_rtc_unload(void)
|
|||
* NAND_CLE: bit 1 -> bit 1
|
||||
* NAND_ALE: bit 2 -> bit 0
|
||||
*/
|
||||
static void ts78xx_ts_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
static void ts78xx_ts_nand_cmd_ctrl(struct nand_chip *this, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
unsigned char bits;
|
||||
|
||||
|
@ -147,19 +144,18 @@ static void ts78xx_ts_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
|||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
writeb(cmd, this->IO_ADDR_W);
|
||||
writeb(cmd, this->legacy.IO_ADDR_W);
|
||||
}
|
||||
|
||||
static int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd)
|
||||
static int ts78xx_ts_nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
return readb(TS_NAND_CTRL) & 0x20;
|
||||
}
|
||||
|
||||
static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
|
||||
static void ts78xx_ts_nand_write_buf(struct nand_chip *chip,
|
||||
const uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
void __iomem *io_base = chip->IO_ADDR_W;
|
||||
void __iomem *io_base = chip->legacy.IO_ADDR_W;
|
||||
unsigned long off = ((unsigned long)buf & 3);
|
||||
int sz;
|
||||
|
||||
|
@ -182,11 +178,10 @@ static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
|
|||
writesb(io_base, buf, len);
|
||||
}
|
||||
|
||||
static void ts78xx_ts_nand_read_buf(struct mtd_info *mtd,
|
||||
static void ts78xx_ts_nand_read_buf(struct nand_chip *chip,
|
||||
uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
void __iomem *io_base = chip->IO_ADDR_R;
|
||||
void __iomem *io_base = chip->legacy.IO_ADDR_R;
|
||||
unsigned long off = ((unsigned long)buf & 3);
|
||||
int sz;
|
||||
|
||||
|
|
|
@ -25,11 +25,10 @@
|
|||
#include <linux/ioport.h>
|
||||
#include <linux/ucb1400.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/platform_data/pcf857x.h>
|
||||
#include <linux/platform_data/i2c-pxa.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/regulator/max1586.h>
|
||||
|
||||
|
@ -571,9 +570,9 @@ static inline void balloon3_i2c_init(void) {}
|
|||
* NAND
|
||||
******************************************************************************/
|
||||
#if defined(CONFIG_MTD_NAND_PLATFORM)||defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
|
||||
static void balloon3_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
static void balloon3_nand_cmd_ctl(struct nand_chip *this, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
uint8_t balloon3_ctl_set = 0, balloon3_ctl_clr = 0;
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
|
@ -597,10 +596,10 @@ static void balloon3_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ct
|
|||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
writeb(cmd, this->IO_ADDR_W);
|
||||
writeb(cmd, this->legacy.IO_ADDR_W);
|
||||
}
|
||||
|
||||
static void balloon3_nand_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void balloon3_nand_select_chip(struct nand_chip *this, int chip)
|
||||
{
|
||||
if (chip < 0 || chip > 3)
|
||||
return;
|
||||
|
@ -616,7 +615,7 @@ static void balloon3_nand_select_chip(struct mtd_info *mtd, int chip)
|
|||
BALLOON3_NAND_CONTROL_REG);
|
||||
}
|
||||
|
||||
static int balloon3_nand_dev_ready(struct mtd_info *mtd)
|
||||
static int balloon3_nand_dev_ready(struct nand_chip *this)
|
||||
{
|
||||
return __raw_readl(BALLOON3_NAND_STAT_REG) & BALLOON3_NAND_STAT_RNB;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
|
||||
#include <linux/dm9000.h>
|
||||
#include <linux/platform_data/rtc-v3020.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
|
@ -285,11 +284,10 @@ static void nand_cs_off(void)
|
|||
}
|
||||
|
||||
/* hardware specific access to control-lines */
|
||||
static void em_x270_nand_cmd_ctl(struct mtd_info *mtd, int dat,
|
||||
static void em_x270_nand_cmd_ctl(struct nand_chip *this, int dat,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
|
||||
unsigned long nandaddr = (unsigned long)this->legacy.IO_ADDR_W;
|
||||
|
||||
dsb();
|
||||
|
||||
|
@ -309,15 +307,15 @@ static void em_x270_nand_cmd_ctl(struct mtd_info *mtd, int dat,
|
|||
}
|
||||
|
||||
dsb();
|
||||
this->IO_ADDR_W = (void __iomem *)nandaddr;
|
||||
this->legacy.IO_ADDR_W = (void __iomem *)nandaddr;
|
||||
if (dat != NAND_CMD_NONE)
|
||||
writel(dat, this->IO_ADDR_W);
|
||||
writel(dat, this->legacy.IO_ADDR_W);
|
||||
|
||||
dsb();
|
||||
}
|
||||
|
||||
/* read device ready pin */
|
||||
static int em_x270_nand_device_ready(struct mtd_info *mtd)
|
||||
static int em_x270_nand_device_ready(struct nand_chip *this)
|
||||
{
|
||||
dsb();
|
||||
|
||||
|
|
|
@ -403,36 +403,6 @@ static void __init palmtreo_leds_init(void)
|
|||
platform_device_register(&palmtreo_leds);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* diskonchip docg4 flash
|
||||
******************************************************************************/
|
||||
#if defined(CONFIG_MACH_TREO680)
|
||||
/* REVISIT: does the centro have this device also? */
|
||||
#if IS_ENABLED(CONFIG_MTD_NAND_DOCG4)
|
||||
static struct resource docg4_resources[] = {
|
||||
{
|
||||
.start = 0x00000000,
|
||||
.end = 0x00001FFF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device treo680_docg4_flash = {
|
||||
.name = "docg4",
|
||||
.id = -1,
|
||||
.resource = docg4_resources,
|
||||
.num_resources = ARRAY_SIZE(docg4_resources),
|
||||
};
|
||||
|
||||
static void __init treo680_docg4_flash_init(void)
|
||||
{
|
||||
platform_device_register(&treo680_docg4_flash);
|
||||
}
|
||||
#else
|
||||
static inline void treo680_docg4_flash_init(void) {}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* Machine init
|
||||
******************************************************************************/
|
||||
|
@ -517,7 +487,6 @@ static void __init treo680_init(void)
|
|||
treo680_gpio_init();
|
||||
palm27x_mmc_init(GPIO_NR_TREO_SD_DETECT_N, GPIO_NR_TREO680_SD_READONLY,
|
||||
GPIO_NR_TREO680_SD_POWER, 0);
|
||||
treo680_docg4_flash_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -28,8 +28,7 @@
|
|||
#include <linux/wm97xx.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/usb/gpio_vbus.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
|
||||
|
@ -247,11 +246,10 @@ static inline void palmtx_keys_init(void) {}
|
|||
******************************************************************************/
|
||||
#if defined(CONFIG_MTD_NAND_PLATFORM) || \
|
||||
defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
|
||||
static void palmtx_nand_cmd_ctl(struct mtd_info *mtd, int cmd,
|
||||
static void palmtx_nand_cmd_ctl(struct nand_chip *this, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
char __iomem *nandaddr = this->IO_ADDR_W;
|
||||
char __iomem *nandaddr = this->legacy.IO_ADDR_W;
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
return;
|
||||
|
|
|
@ -29,8 +29,7 @@
|
|||
#include <linux/leds.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
@ -197,11 +196,10 @@ static struct i2c_board_info db1200_i2c_devs[] __initdata = {
|
|||
|
||||
/**********************************************************************/
|
||||
|
||||
static void au1200_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
static void au1200_nand_cmd_ctrl(struct nand_chip *this, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
|
||||
unsigned long ioaddr = (unsigned long)this->legacy.IO_ADDR_W;
|
||||
|
||||
ioaddr &= 0xffffff00;
|
||||
|
||||
|
@ -213,14 +211,14 @@ static void au1200_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
|||
/* assume we want to r/w real data by default */
|
||||
ioaddr += MEM_STNAND_DATA;
|
||||
}
|
||||
this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
|
||||
this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = (void __iomem *)ioaddr;
|
||||
if (cmd != NAND_CMD_NONE) {
|
||||
__raw_writeb(cmd, this->IO_ADDR_W);
|
||||
__raw_writeb(cmd, this->legacy.IO_ADDR_W);
|
||||
wmb();
|
||||
}
|
||||
}
|
||||
|
||||
static int au1200_nand_device_ready(struct mtd_info *mtd)
|
||||
static int au1200_nand_device_ready(struct nand_chip *this)
|
||||
{
|
||||
return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1;
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
#include <linux/mmc/host.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/smsc911x.h>
|
||||
#include <linux/wm97xx.h>
|
||||
|
@ -149,11 +148,10 @@ static void __init db1300_gpio_config(void)
|
|||
|
||||
/**********************************************************************/
|
||||
|
||||
static void au1300_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
static void au1300_nand_cmd_ctrl(struct nand_chip *this, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
|
||||
unsigned long ioaddr = (unsigned long)this->legacy.IO_ADDR_W;
|
||||
|
||||
ioaddr &= 0xffffff00;
|
||||
|
||||
|
@ -165,14 +163,14 @@ static void au1300_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
|||
/* assume we want to r/w real data by default */
|
||||
ioaddr += MEM_STNAND_DATA;
|
||||
}
|
||||
this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
|
||||
this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = (void __iomem *)ioaddr;
|
||||
if (cmd != NAND_CMD_NONE) {
|
||||
__raw_writeb(cmd, this->IO_ADDR_W);
|
||||
__raw_writeb(cmd, this->legacy.IO_ADDR_W);
|
||||
wmb();
|
||||
}
|
||||
}
|
||||
|
||||
static int au1300_nand_device_ready(struct mtd_info *mtd)
|
||||
static int au1300_nand_device_ready(struct nand_chip *this)
|
||||
{
|
||||
return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1;
|
||||
}
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
@ -126,11 +125,10 @@ static struct i2c_board_info db1550_i2c_devs[] __initdata = {
|
|||
|
||||
/**********************************************************************/
|
||||
|
||||
static void au1550_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
static void au1550_nand_cmd_ctrl(struct nand_chip *this, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
|
||||
unsigned long ioaddr = (unsigned long)this->legacy.IO_ADDR_W;
|
||||
|
||||
ioaddr &= 0xffffff00;
|
||||
|
||||
|
@ -142,14 +140,14 @@ static void au1550_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
|||
/* assume we want to r/w real data by default */
|
||||
ioaddr += MEM_STNAND_DATA;
|
||||
}
|
||||
this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
|
||||
this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = (void __iomem *)ioaddr;
|
||||
if (cmd != NAND_CMD_NONE) {
|
||||
__raw_writeb(cmd, this->IO_ADDR_W);
|
||||
__raw_writeb(cmd, this->legacy.IO_ADDR_W);
|
||||
wmb();
|
||||
}
|
||||
}
|
||||
|
||||
static int au1550_nand_device_ready(struct mtd_info *mtd)
|
||||
static int au1550_nand_device_ready(struct nand_chip *this)
|
||||
{
|
||||
return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1;
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
|
||||
#include <asm/netlogic/haldefs.h>
|
||||
#include <asm/netlogic/xlr/iomap.h>
|
||||
|
@ -92,7 +91,7 @@ struct xlr_nand_flash_priv {
|
|||
|
||||
static struct xlr_nand_flash_priv nand_priv;
|
||||
|
||||
static void xlr_nand_ctrl(struct mtd_info *mtd, int cmd,
|
||||
static void xlr_nand_ctrl(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
if (ctrl & NAND_CLE)
|
||||
|
|
|
@ -30,8 +30,7 @@
|
|||
#include <linux/resource.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_pnx8xxx.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
|
||||
#include <irq.h>
|
||||
#include <irq-mapping.h>
|
||||
|
@ -178,10 +177,9 @@ static struct platform_device pnx833x_sata_device = {
|
|||
};
|
||||
|
||||
static void
|
||||
pnx833x_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
pnx833x_flash_nand_cmd_ctrl(struct nand_chip *this, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
|
||||
unsigned long nandaddr = (unsigned long)this->legacy.IO_ADDR_W;
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
return;
|
||||
|
|
|
@ -20,9 +20,8 @@
|
|||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/input.h>
|
||||
|
@ -141,14 +140,13 @@ static struct platform_device cf_slot0 = {
|
|||
};
|
||||
|
||||
/* Resources and device for NAND */
|
||||
static int rb532_dev_ready(struct mtd_info *mtd)
|
||||
static int rb532_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
return gpio_get_value(GPIO_RDY);
|
||||
}
|
||||
|
||||
static void rb532_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
static void rb532_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
unsigned char orbits, nandbits;
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
|
@ -161,7 +159,7 @@ static void rb532_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
|||
set_latch_u5(orbits, nandbits);
|
||||
}
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
writeb(cmd, chip->IO_ADDR_W);
|
||||
writeb(cmd, chip->legacy.IO_ADDR_W);
|
||||
}
|
||||
|
||||
static struct resource nand_slot0_res[] = {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <linux/mmc/host.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/mfd/tmio.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regulator/fixed.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
@ -165,23 +165,21 @@ static struct mtd_partition migor_nand_flash_partitions[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static void migor_nand_flash_cmd_ctl(struct mtd_info *mtd, int cmd,
|
||||
static void migor_nand_flash_cmd_ctl(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
return;
|
||||
|
||||
if (ctrl & NAND_CLE)
|
||||
writeb(cmd, chip->IO_ADDR_W + 0x00400000);
|
||||
writeb(cmd, chip->legacy.IO_ADDR_W + 0x00400000);
|
||||
else if (ctrl & NAND_ALE)
|
||||
writeb(cmd, chip->IO_ADDR_W + 0x00800000);
|
||||
writeb(cmd, chip->legacy.IO_ADDR_W + 0x00800000);
|
||||
else
|
||||
writeb(cmd, chip->IO_ADDR_W);
|
||||
writeb(cmd, chip->legacy.IO_ADDR_W);
|
||||
}
|
||||
|
||||
static int migor_nand_flash_ready(struct mtd_info *mtd)
|
||||
static int migor_nand_flash_ready(struct nand_chip *chip)
|
||||
{
|
||||
return gpio_get_value(GPIO_PTA1); /* NAND_RBn */
|
||||
}
|
||||
|
|
|
@ -90,7 +90,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
|
|||
SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 1));
|
||||
size_t remaining = len;
|
||||
int ret;
|
||||
|
||||
/* get transfer protocols. */
|
||||
|
@ -101,22 +100,16 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
|
|||
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
|
||||
op.addr.nbytes = 0;
|
||||
|
||||
while (remaining) {
|
||||
op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
|
||||
ret = spi_mem_adjust_op_size(flash->spimem, &op);
|
||||
if (ret)
|
||||
return ret;
|
||||
op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
|
||||
|
||||
ret = spi_mem_exec_op(flash->spimem, &op);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
op.addr.val += op.data.nbytes;
|
||||
remaining -= op.data.nbytes;
|
||||
op.data.buf.out += op.data.nbytes;
|
||||
}
|
||||
|
||||
return len;
|
||||
return op.data.nbytes;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -25,28 +26,24 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define pr_devinit(fmt, args...) \
|
||||
({ static const char __fmt[] = fmt; printk(__fmt, ## args); })
|
||||
#define win_mask(x) ((BIT(x)) - 1)
|
||||
|
||||
#define DRIVER_NAME "gpio-addr-flash"
|
||||
#define PFX DRIVER_NAME ": "
|
||||
|
||||
/**
|
||||
* struct async_state - keep GPIO flash state
|
||||
* @mtd: MTD state for this mapping
|
||||
* @map: MTD map state for this flash
|
||||
* @gpio_count: number of GPIOs used to address
|
||||
* @gpio_addrs: array of GPIOs to twiddle
|
||||
* @gpios: Struct containing the array of GPIO descriptors
|
||||
* @gpio_values: cached GPIO values
|
||||
* @win_size: dedicated memory size (if no GPIOs)
|
||||
* @win_order: dedicated memory size (if no GPIOs)
|
||||
*/
|
||||
struct async_state {
|
||||
struct mtd_info *mtd;
|
||||
struct map_info map;
|
||||
size_t gpio_count;
|
||||
unsigned *gpio_addrs;
|
||||
int *gpio_values;
|
||||
unsigned long win_size;
|
||||
struct gpio_descs *gpios;
|
||||
unsigned int gpio_values;
|
||||
unsigned int win_order;
|
||||
};
|
||||
#define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1)
|
||||
|
||||
|
@ -57,21 +54,25 @@ struct async_state {
|
|||
*
|
||||
* Rather than call the GPIO framework every time, cache the last-programmed
|
||||
* value. This speeds up sequential accesses (which are by far the most common
|
||||
* type). We rely on the GPIO framework to treat non-zero value as high so
|
||||
* that we don't have to normalize the bits.
|
||||
* type).
|
||||
*/
|
||||
static void gf_set_gpios(struct async_state *state, unsigned long ofs)
|
||||
{
|
||||
size_t i = 0;
|
||||
int value;
|
||||
ofs /= state->win_size;
|
||||
do {
|
||||
value = ofs & (1 << i);
|
||||
if (state->gpio_values[i] != value) {
|
||||
gpio_set_value(state->gpio_addrs[i], value);
|
||||
state->gpio_values[i] = value;
|
||||
int i;
|
||||
|
||||
ofs >>= state->win_order;
|
||||
|
||||
if (ofs == state->gpio_values)
|
||||
return;
|
||||
|
||||
for (i = 0; i < state->gpios->ndescs; i++) {
|
||||
if ((ofs & BIT(i)) == (state->gpio_values & BIT(i)))
|
||||
continue;
|
||||
|
||||
gpiod_set_value(state->gpios->desc[i], !!(ofs & BIT(i)));
|
||||
}
|
||||
} while (++i < state->gpio_count);
|
||||
|
||||
state->gpio_values = ofs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,7 +88,7 @@ static map_word gf_read(struct map_info *map, unsigned long ofs)
|
|||
|
||||
gf_set_gpios(state, ofs);
|
||||
|
||||
word = readw(map->virt + (ofs % state->win_size));
|
||||
word = readw(map->virt + (ofs & win_mask(state->win_order)));
|
||||
test.x[0] = word;
|
||||
return test;
|
||||
}
|
||||
|
@ -109,13 +110,13 @@ static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssi
|
|||
int this_len;
|
||||
|
||||
while (len) {
|
||||
if ((from % state->win_size) + len > state->win_size)
|
||||
this_len = state->win_size - (from % state->win_size);
|
||||
else
|
||||
this_len = len;
|
||||
this_len = from & win_mask(state->win_order);
|
||||
this_len = BIT(state->win_order) - this_len;
|
||||
this_len = min_t(int, len, this_len);
|
||||
|
||||
gf_set_gpios(state, from);
|
||||
memcpy_fromio(to, map->virt + (from % state->win_size),
|
||||
memcpy_fromio(to,
|
||||
map->virt + (from & win_mask(state->win_order)),
|
||||
this_len);
|
||||
len -= this_len;
|
||||
from += this_len;
|
||||
|
@ -136,7 +137,7 @@ static void gf_write(struct map_info *map, map_word d1, unsigned long ofs)
|
|||
gf_set_gpios(state, ofs);
|
||||
|
||||
d = d1.x[0];
|
||||
writew(d, map->virt + (ofs % state->win_size));
|
||||
writew(d, map->virt + (ofs & win_mask(state->win_order)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,13 +157,13 @@ static void gf_copy_to(struct map_info *map, unsigned long to,
|
|||
int this_len;
|
||||
|
||||
while (len) {
|
||||
if ((to % state->win_size) + len > state->win_size)
|
||||
this_len = state->win_size - (to % state->win_size);
|
||||
else
|
||||
this_len = len;
|
||||
this_len = to & win_mask(state->win_order);
|
||||
this_len = BIT(state->win_order) - this_len;
|
||||
this_len = min_t(int, len, this_len);
|
||||
|
||||
gf_set_gpios(state, to);
|
||||
memcpy_toio(map->virt + (to % state->win_size), from, len);
|
||||
memcpy_toio(map->virt + (to & win_mask(state->win_order)),
|
||||
from, len);
|
||||
|
||||
len -= this_len;
|
||||
to += this_len;
|
||||
|
@ -180,18 +181,22 @@ static const char * const part_probe_types[] = {
|
|||
* The platform resource layout expected looks something like:
|
||||
* struct mtd_partition partitions[] = { ... };
|
||||
* struct physmap_flash_data flash_data = { ... };
|
||||
* unsigned flash_gpios[] = { GPIO_XX, GPIO_XX, ... };
|
||||
* static struct gpiod_lookup_table addr_flash_gpios = {
|
||||
* .dev_id = "gpio-addr-flash.0",
|
||||
* .table = {
|
||||
* GPIO_LOOKUP_IDX("gpio.0", 15, "addr", 0, GPIO_ACTIVE_HIGH),
|
||||
* GPIO_LOOKUP_IDX("gpio.0", 16, "addr", 1, GPIO_ACTIVE_HIGH),
|
||||
* );
|
||||
* };
|
||||
* gpiod_add_lookup_table(&addr_flash_gpios);
|
||||
*
|
||||
* struct resource flash_resource[] = {
|
||||
* {
|
||||
* .name = "cfi_probe",
|
||||
* .start = 0x20000000,
|
||||
* .end = 0x201fffff,
|
||||
* .flags = IORESOURCE_MEM,
|
||||
* }, {
|
||||
* .start = (unsigned long)flash_gpios,
|
||||
* .end = ARRAY_SIZE(flash_gpios),
|
||||
* .flags = IORESOURCE_IRQ,
|
||||
* }
|
||||
* },
|
||||
* };
|
||||
* struct platform_device flash_device = {
|
||||
* .name = "gpio-addr-flash",
|
||||
|
@ -203,33 +208,25 @@ static const char * const part_probe_types[] = {
|
|||
*/
|
||||
static int gpio_flash_probe(struct platform_device *pdev)
|
||||
{
|
||||
size_t i, arr_size;
|
||||
struct physmap_flash_data *pdata;
|
||||
struct resource *memory;
|
||||
struct resource *gpios;
|
||||
struct async_state *state;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
|
||||
if (!memory || !gpios || !gpios->end)
|
||||
if (!memory)
|
||||
return -EINVAL;
|
||||
|
||||
arr_size = sizeof(int) * gpios->end;
|
||||
state = kzalloc(sizeof(*state) + arr_size, GFP_KERNEL);
|
||||
state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* We cast start/end to known types in the boards file, so cast
|
||||
* away their pointer types here to the known types (gpios->xxx).
|
||||
*/
|
||||
state->gpio_count = gpios->end;
|
||||
state->gpio_addrs = (void *)(unsigned long)gpios->start;
|
||||
state->gpio_values = (void *)(state + 1);
|
||||
state->win_size = resource_size(memory);
|
||||
memset(state->gpio_values, 0xff, arr_size);
|
||||
state->gpios = devm_gpiod_get_array(&pdev->dev, "addr", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(state->gpios))
|
||||
return PTR_ERR(state->gpios);
|
||||
|
||||
state->win_order = get_bitmask_order(resource_size(memory)) - 1;
|
||||
|
||||
state->map.name = DRIVER_NAME;
|
||||
state->map.read = gf_read;
|
||||
|
@ -237,38 +234,21 @@ static int gpio_flash_probe(struct platform_device *pdev)
|
|||
state->map.write = gf_write;
|
||||
state->map.copy_to = gf_copy_to;
|
||||
state->map.bankwidth = pdata->width;
|
||||
state->map.size = state->win_size * (1 << state->gpio_count);
|
||||
state->map.virt = ioremap_nocache(memory->start, state->map.size);
|
||||
if (!state->map.virt)
|
||||
return -ENOMEM;
|
||||
state->map.size = BIT(state->win_order + state->gpios->ndescs);
|
||||
state->map.virt = devm_ioremap_resource(&pdev->dev, memory);
|
||||
if (IS_ERR(state->map.virt))
|
||||
return PTR_ERR(state->map.virt);
|
||||
|
||||
state->map.phys = NO_XIP;
|
||||
state->map.map_priv_1 = (unsigned long)state;
|
||||
|
||||
platform_set_drvdata(pdev, state);
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
if (gpio_request(state->gpio_addrs[i], DRIVER_NAME)) {
|
||||
pr_devinit(KERN_ERR PFX "failed to request gpio %d\n",
|
||||
state->gpio_addrs[i]);
|
||||
while (i--)
|
||||
gpio_free(state->gpio_addrs[i]);
|
||||
kfree(state);
|
||||
return -EBUSY;
|
||||
}
|
||||
gpio_direction_output(state->gpio_addrs[i], 0);
|
||||
} while (++i < state->gpio_count);
|
||||
|
||||
pr_devinit(KERN_NOTICE PFX "probing %d-bit flash bus\n",
|
||||
dev_notice(&pdev->dev, "probing %d-bit flash bus\n",
|
||||
state->map.bankwidth * 8);
|
||||
state->mtd = do_map_probe(memory->name, &state->map);
|
||||
if (!state->mtd) {
|
||||
for (i = 0; i < state->gpio_count; ++i)
|
||||
gpio_free(state->gpio_addrs[i]);
|
||||
kfree(state);
|
||||
if (!state->mtd)
|
||||
return -ENXIO;
|
||||
}
|
||||
state->mtd->dev.parent = &pdev->dev;
|
||||
|
||||
mtd_device_parse_register(state->mtd, part_probe_types, NULL,
|
||||
|
@ -280,13 +260,9 @@ static int gpio_flash_probe(struct platform_device *pdev)
|
|||
static int gpio_flash_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct async_state *state = platform_get_drvdata(pdev);
|
||||
size_t i = 0;
|
||||
do {
|
||||
gpio_free(state->gpio_addrs[i]);
|
||||
} while (++i < state->gpio_count);
|
||||
|
||||
mtd_device_unregister(state->mtd);
|
||||
map_destroy(state->mtd);
|
||||
kfree(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
struct of_flash_list {
|
||||
struct mtd_info *mtd;
|
||||
struct map_info map;
|
||||
struct resource *res;
|
||||
};
|
||||
|
||||
struct of_flash {
|
||||
|
@ -56,18 +55,10 @@ static int of_flash_remove(struct platform_device *dev)
|
|||
mtd_concat_destroy(info->cmtd);
|
||||
}
|
||||
|
||||
for (i = 0; i < info->list_size; i++) {
|
||||
for (i = 0; i < info->list_size; i++)
|
||||
if (info->list[i].mtd)
|
||||
map_destroy(info->list[i].mtd);
|
||||
|
||||
if (info->list[i].map.virt)
|
||||
iounmap(info->list[i].map.virt);
|
||||
|
||||
if (info->list[i].res) {
|
||||
release_resource(info->list[i].res);
|
||||
kfree(info->list[i].res);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -215,10 +206,11 @@ static int of_flash_probe(struct platform_device *dev)
|
|||
|
||||
err = -EBUSY;
|
||||
res_size = resource_size(&res);
|
||||
info->list[i].res = request_mem_region(res.start, res_size,
|
||||
dev_name(&dev->dev));
|
||||
if (!info->list[i].res)
|
||||
info->list[i].map.virt = devm_ioremap_resource(&dev->dev, &res);
|
||||
if (IS_ERR(info->list[i].map.virt)) {
|
||||
err = PTR_ERR(info->list[i].map.virt);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
err = -ENXIO;
|
||||
width = of_get_property(dp, "bank-width", NULL);
|
||||
|
@ -246,15 +238,6 @@ static int of_flash_probe(struct platform_device *dev)
|
|||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = -ENOMEM;
|
||||
info->list[i].map.virt = ioremap(info->list[i].map.phys,
|
||||
info->list[i].map.size);
|
||||
if (!info->list[i].map.virt) {
|
||||
dev_err(&dev->dev, "Failed to ioremap() flash"
|
||||
" region\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
simple_map_init(&info->list[i].map);
|
||||
|
||||
/*
|
||||
|
|
|
@ -44,11 +44,6 @@
|
|||
|
||||
#define FLASH_PARALLEL_HIGH_PIN_CNT (1 << 20) /* else low pin cnt */
|
||||
|
||||
static const struct of_device_id syscon_match[] = {
|
||||
{ .compatible = "cortina,gemini-syscon" },
|
||||
{ },
|
||||
};
|
||||
|
||||
int of_flash_probe_gemini(struct platform_device *pdev,
|
||||
struct device_node *np,
|
||||
struct map_info *map)
|
||||
|
|
|
@ -227,26 +227,6 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
|
|||
load time (assuming you build diskonchip as a module) with the module
|
||||
parameter "inftl_bbt_write=1".
|
||||
|
||||
config MTD_NAND_DOCG4
|
||||
tristate "Support for DiskOnChip G4"
|
||||
depends on HAS_IOMEM
|
||||
select BCH
|
||||
select BITREVERSE
|
||||
help
|
||||
Support for diskonchip G4 nand flash, found in various smartphones and
|
||||
PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba
|
||||
Portege G900, Asus P526, and O2 XDA Zinc.
|
||||
|
||||
With this driver you will be able to use UBI and create a ubifs on the
|
||||
device, so you may wish to consider enabling UBI and UBIFS as well.
|
||||
|
||||
These devices ship with the Mys/Sandisk SAFTL formatting, for which
|
||||
there is currently no mtd parser, so you may want to use command line
|
||||
partitioning to segregate write-protected blocks. On the Treo680, the
|
||||
first five erase blocks (256KiB each) are write-protected, followed
|
||||
by the block containing the saftl partition table. This is probably
|
||||
typical.
|
||||
|
||||
config MTD_NAND_SHARPSL
|
||||
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
|
||||
depends on ARCH_PXA || COMPILE_TEST
|
||||
|
|
|
@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
|
|||
obj-$(CONFIG_MTD_NAND_TANGO) += tango_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
|
||||
obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o
|
||||
obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
|
||||
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
|
||||
|
@ -58,8 +57,11 @@ obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
|
|||
obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o
|
||||
|
||||
nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o
|
||||
nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
|
||||
nand-objs += nand_onfi.o
|
||||
nand-objs += nand_jedec.o
|
||||
nand-objs += nand_amd.o
|
||||
nand-objs += nand_esmt.o
|
||||
nand-objs += nand_hynix.o
|
||||
nand-objs += nand_macronix.o
|
||||
nand-objs += nand_micron.o
|
||||
|
|
|
@ -20,23 +20,33 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_data/gpio-omap.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/sizes.h>
|
||||
|
||||
#include <mach/board-ams-delta.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
/*
|
||||
* MTD structure for E3 (Delta)
|
||||
*/
|
||||
static struct mtd_info *ams_delta_mtd = NULL;
|
||||
|
||||
struct ams_delta_nand {
|
||||
struct nand_chip nand_chip;
|
||||
struct gpio_desc *gpiod_rdy;
|
||||
struct gpio_desc *gpiod_nce;
|
||||
struct gpio_desc *gpiod_nre;
|
||||
struct gpio_desc *gpiod_nwp;
|
||||
struct gpio_desc *gpiod_nwe;
|
||||
struct gpio_desc *gpiod_ale;
|
||||
struct gpio_desc *gpiod_cle;
|
||||
void __iomem *io_base;
|
||||
bool data_in;
|
||||
};
|
||||
|
||||
/*
|
||||
* Define partitions for flash devices
|
||||
|
@ -63,48 +73,64 @@ static const struct mtd_partition partition_info[] = {
|
|||
.size = 3 * SZ_256K },
|
||||
};
|
||||
|
||||
static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
|
||||
static void ams_delta_io_write(struct ams_delta_nand *priv, u_char byte)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
|
||||
|
||||
writew(0, io_base + OMAP_MPUIO_IO_CNTL);
|
||||
writew(byte, this->IO_ADDR_W);
|
||||
gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 0);
|
||||
writew(byte, priv->nand_chip.legacy.IO_ADDR_W);
|
||||
gpiod_set_value(priv->gpiod_nwe, 0);
|
||||
ndelay(40);
|
||||
gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 1);
|
||||
gpiod_set_value(priv->gpiod_nwe, 1);
|
||||
}
|
||||
|
||||
static u_char ams_delta_read_byte(struct mtd_info *mtd)
|
||||
static u_char ams_delta_io_read(struct ams_delta_nand *priv)
|
||||
{
|
||||
u_char res;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
void __iomem *io_base = (void __iomem *)nand_get_controller_data(this);
|
||||
|
||||
gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0);
|
||||
gpiod_set_value(priv->gpiod_nre, 0);
|
||||
ndelay(40);
|
||||
writew(~0, io_base + OMAP_MPUIO_IO_CNTL);
|
||||
res = readw(this->IO_ADDR_R);
|
||||
gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 1);
|
||||
res = readw(priv->nand_chip.legacy.IO_ADDR_R);
|
||||
gpiod_set_value(priv->gpiod_nre, 1);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
|
||||
int len)
|
||||
static void ams_delta_dir_input(struct ams_delta_nand *priv, bool in)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<len; i++)
|
||||
ams_delta_write_byte(mtd, buf[i]);
|
||||
writew(in ? ~0 : 0, priv->io_base + OMAP_MPUIO_IO_CNTL);
|
||||
priv->data_in = in;
|
||||
}
|
||||
|
||||
static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void ams_delta_write_buf(struct nand_chip *this, const u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct ams_delta_nand *priv = nand_get_controller_data(this);
|
||||
int i;
|
||||
|
||||
for (i=0; i<len; i++)
|
||||
buf[i] = ams_delta_read_byte(mtd);
|
||||
if (priv->data_in)
|
||||
ams_delta_dir_input(priv, false);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
ams_delta_io_write(priv, buf[i]);
|
||||
}
|
||||
|
||||
static void ams_delta_read_buf(struct nand_chip *this, u_char *buf, int len)
|
||||
{
|
||||
struct ams_delta_nand *priv = nand_get_controller_data(this);
|
||||
int i;
|
||||
|
||||
if (!priv->data_in)
|
||||
ams_delta_dir_input(priv, true);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = ams_delta_io_read(priv);
|
||||
}
|
||||
|
||||
static u_char ams_delta_read_byte(struct nand_chip *this)
|
||||
{
|
||||
u_char res;
|
||||
|
||||
ams_delta_read_buf(this, &res, 1);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -115,67 +141,40 @@ static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
|||
* NAND_CLE: bit 1 -> bit 7
|
||||
* NAND_ALE: bit 2 -> bit 6
|
||||
*/
|
||||
static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
static void ams_delta_hwcontrol(struct nand_chip *this, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct ams_delta_nand *priv = nand_get_controller_data(this);
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NCE,
|
||||
(ctrl & NAND_NCE) == 0);
|
||||
gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_CLE,
|
||||
(ctrl & NAND_CLE) != 0);
|
||||
gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_ALE,
|
||||
(ctrl & NAND_ALE) != 0);
|
||||
gpiod_set_value(priv->gpiod_nce, !(ctrl & NAND_NCE));
|
||||
gpiod_set_value(priv->gpiod_cle, !!(ctrl & NAND_CLE));
|
||||
gpiod_set_value(priv->gpiod_ale, !!(ctrl & NAND_ALE));
|
||||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
ams_delta_write_byte(mtd, cmd);
|
||||
if (cmd != NAND_CMD_NONE) {
|
||||
u_char byte = cmd;
|
||||
|
||||
ams_delta_write_buf(this, &byte, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int ams_delta_nand_ready(struct mtd_info *mtd)
|
||||
static int ams_delta_nand_ready(struct nand_chip *this)
|
||||
{
|
||||
return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
|
||||
struct ams_delta_nand *priv = nand_get_controller_data(this);
|
||||
|
||||
return gpiod_get_value(priv->gpiod_rdy);
|
||||
}
|
||||
|
||||
static const struct gpio _mandatory_gpio[] = {
|
||||
{
|
||||
.gpio = AMS_DELTA_GPIO_PIN_NAND_NCE,
|
||||
.flags = GPIOF_OUT_INIT_HIGH,
|
||||
.label = "nand_nce",
|
||||
},
|
||||
{
|
||||
.gpio = AMS_DELTA_GPIO_PIN_NAND_NRE,
|
||||
.flags = GPIOF_OUT_INIT_HIGH,
|
||||
.label = "nand_nre",
|
||||
},
|
||||
{
|
||||
.gpio = AMS_DELTA_GPIO_PIN_NAND_NWP,
|
||||
.flags = GPIOF_OUT_INIT_HIGH,
|
||||
.label = "nand_nwp",
|
||||
},
|
||||
{
|
||||
.gpio = AMS_DELTA_GPIO_PIN_NAND_NWE,
|
||||
.flags = GPIOF_OUT_INIT_HIGH,
|
||||
.label = "nand_nwe",
|
||||
},
|
||||
{
|
||||
.gpio = AMS_DELTA_GPIO_PIN_NAND_ALE,
|
||||
.flags = GPIOF_OUT_INIT_LOW,
|
||||
.label = "nand_ale",
|
||||
},
|
||||
{
|
||||
.gpio = AMS_DELTA_GPIO_PIN_NAND_CLE,
|
||||
.flags = GPIOF_OUT_INIT_LOW,
|
||||
.label = "nand_cle",
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Main initialization routine
|
||||
*/
|
||||
static int ams_delta_init(struct platform_device *pdev)
|
||||
{
|
||||
struct ams_delta_nand *priv;
|
||||
struct nand_chip *this;
|
||||
struct mtd_info *mtd;
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
void __iomem *io_base;
|
||||
int err = 0;
|
||||
|
@ -184,15 +183,16 @@ static int ams_delta_init(struct platform_device *pdev)
|
|||
return -ENXIO;
|
||||
|
||||
/* Allocate memory for MTD device structure and private data */
|
||||
this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
|
||||
if (!this) {
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(struct ams_delta_nand),
|
||||
GFP_KERNEL);
|
||||
if (!priv) {
|
||||
pr_warn("Unable to allocate E3 NAND MTD device structure.\n");
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
return -ENOMEM;
|
||||
}
|
||||
this = &priv->nand_chip;
|
||||
|
||||
ams_delta_mtd = nand_to_mtd(this);
|
||||
ams_delta_mtd->owner = THIS_MODULE;
|
||||
mtd = nand_to_mtd(this);
|
||||
mtd->dev.parent = &pdev->dev;
|
||||
|
||||
/*
|
||||
* Don't try to request the memory region from here,
|
||||
|
@ -207,51 +207,93 @@ static int ams_delta_init(struct platform_device *pdev)
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
nand_set_controller_data(this, (void *)io_base);
|
||||
priv->io_base = io_base;
|
||||
nand_set_controller_data(this, priv);
|
||||
|
||||
/* Set address of NAND IO lines */
|
||||
this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
|
||||
this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
|
||||
this->read_byte = ams_delta_read_byte;
|
||||
this->write_buf = ams_delta_write_buf;
|
||||
this->read_buf = ams_delta_read_buf;
|
||||
this->cmd_ctrl = ams_delta_hwcontrol;
|
||||
if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
|
||||
this->dev_ready = ams_delta_nand_ready;
|
||||
} else {
|
||||
this->dev_ready = NULL;
|
||||
pr_notice("Couldn't request gpio for Delta NAND ready.\n");
|
||||
this->legacy.IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
|
||||
this->legacy.IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
|
||||
this->legacy.read_byte = ams_delta_read_byte;
|
||||
this->legacy.write_buf = ams_delta_write_buf;
|
||||
this->legacy.read_buf = ams_delta_read_buf;
|
||||
this->legacy.cmd_ctrl = ams_delta_hwcontrol;
|
||||
|
||||
priv->gpiod_rdy = devm_gpiod_get_optional(&pdev->dev, "rdy", GPIOD_IN);
|
||||
if (IS_ERR(priv->gpiod_rdy)) {
|
||||
err = PTR_ERR(priv->gpiod_rdy);
|
||||
dev_warn(&pdev->dev, "RDY GPIO request failed (%d)\n", err);
|
||||
goto out_mtd;
|
||||
}
|
||||
|
||||
if (priv->gpiod_rdy)
|
||||
this->legacy.dev_ready = ams_delta_nand_ready;
|
||||
|
||||
/* 25 us command delay time */
|
||||
this->chip_delay = 30;
|
||||
this->legacy.chip_delay = 30;
|
||||
this->ecc.mode = NAND_ECC_SOFT;
|
||||
this->ecc.algo = NAND_ECC_HAMMING;
|
||||
|
||||
platform_set_drvdata(pdev, io_base);
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
/* Set chip enabled, but */
|
||||
err = gpio_request_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
|
||||
if (err)
|
||||
goto out_gpio;
|
||||
priv->gpiod_nwp = devm_gpiod_get(&pdev->dev, "nwp", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(priv->gpiod_nwp)) {
|
||||
err = PTR_ERR(priv->gpiod_nwp);
|
||||
dev_err(&pdev->dev, "NWP GPIO request failed (%d)\n", err);
|
||||
goto out_mtd;
|
||||
}
|
||||
|
||||
priv->gpiod_nce = devm_gpiod_get(&pdev->dev, "nce", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(priv->gpiod_nce)) {
|
||||
err = PTR_ERR(priv->gpiod_nce);
|
||||
dev_err(&pdev->dev, "NCE GPIO request failed (%d)\n", err);
|
||||
goto out_mtd;
|
||||
}
|
||||
|
||||
priv->gpiod_nre = devm_gpiod_get(&pdev->dev, "nre", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(priv->gpiod_nre)) {
|
||||
err = PTR_ERR(priv->gpiod_nre);
|
||||
dev_err(&pdev->dev, "NRE GPIO request failed (%d)\n", err);
|
||||
goto out_mtd;
|
||||
}
|
||||
|
||||
priv->gpiod_nwe = devm_gpiod_get(&pdev->dev, "nwe", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(priv->gpiod_nwe)) {
|
||||
err = PTR_ERR(priv->gpiod_nwe);
|
||||
dev_err(&pdev->dev, "NWE GPIO request failed (%d)\n", err);
|
||||
goto out_mtd;
|
||||
}
|
||||
|
||||
priv->gpiod_ale = devm_gpiod_get(&pdev->dev, "ale", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(priv->gpiod_ale)) {
|
||||
err = PTR_ERR(priv->gpiod_ale);
|
||||
dev_err(&pdev->dev, "ALE GPIO request failed (%d)\n", err);
|
||||
goto out_mtd;
|
||||
}
|
||||
|
||||
priv->gpiod_cle = devm_gpiod_get(&pdev->dev, "cle", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(priv->gpiod_cle)) {
|
||||
err = PTR_ERR(priv->gpiod_cle);
|
||||
dev_err(&pdev->dev, "CLE GPIO request failed (%d)\n", err);
|
||||
goto out_mtd;
|
||||
}
|
||||
|
||||
/* Initialize data port direction to a known state */
|
||||
ams_delta_dir_input(priv, true);
|
||||
|
||||
/* Scan to find existence of the device */
|
||||
err = nand_scan(ams_delta_mtd, 1);
|
||||
err = nand_scan(this, 1);
|
||||
if (err)
|
||||
goto out_mtd;
|
||||
|
||||
/* Register the partitions */
|
||||
mtd_device_register(ams_delta_mtd, partition_info,
|
||||
ARRAY_SIZE(partition_info));
|
||||
mtd_device_register(mtd, partition_info, ARRAY_SIZE(partition_info));
|
||||
|
||||
goto out;
|
||||
|
||||
out_mtd:
|
||||
gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
|
||||
out_gpio:
|
||||
gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
|
||||
iounmap(io_base);
|
||||
out_free:
|
||||
kfree(this);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
@ -261,18 +303,15 @@ out_free:
|
|||
*/
|
||||
static int ams_delta_cleanup(struct platform_device *pdev)
|
||||
{
|
||||
void __iomem *io_base = platform_get_drvdata(pdev);
|
||||
struct ams_delta_nand *priv = platform_get_drvdata(pdev);
|
||||
struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip);
|
||||
void __iomem *io_base = priv->io_base;
|
||||
|
||||
/* Release resources, unregister device */
|
||||
nand_release(ams_delta_mtd);
|
||||
nand_release(mtd_to_nand(mtd));
|
||||
|
||||
gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
|
||||
gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
|
||||
iounmap(io_base);
|
||||
|
||||
/* Free the MTD device structure */
|
||||
kfree(mtd_to_nand(ams_delta_mtd));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -410,25 +410,15 @@ err:
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static u8 atmel_nand_read_byte(struct mtd_info *mtd)
|
||||
static u8 atmel_nand_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
|
||||
return ioread8(nand->activecs->io.virt);
|
||||
}
|
||||
|
||||
static u16 atmel_nand_read_word(struct mtd_info *mtd)
|
||||
static void atmel_nand_write_byte(struct nand_chip *chip, u8 byte)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
|
||||
return ioread16(nand->activecs->io.virt);
|
||||
}
|
||||
|
||||
static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
|
||||
if (chip->options & NAND_BUSWIDTH_16)
|
||||
|
@ -437,9 +427,8 @@ static void atmel_nand_write_byte(struct mtd_info *mtd, u8 byte)
|
|||
iowrite8(byte, nand->activecs->io.virt);
|
||||
}
|
||||
|
||||
static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
||||
static void atmel_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
struct atmel_nand_controller *nc;
|
||||
|
||||
|
@ -462,9 +451,8 @@ static void atmel_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
|||
ioread8_rep(nand->activecs->io.virt, buf, len);
|
||||
}
|
||||
|
||||
static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
||||
static void atmel_nand_write_buf(struct nand_chip *chip, const u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
struct atmel_nand_controller *nc;
|
||||
|
||||
|
@ -487,34 +475,31 @@ static void atmel_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
|||
iowrite8_rep(nand->activecs->io.virt, buf, len);
|
||||
}
|
||||
|
||||
static int atmel_nand_dev_ready(struct mtd_info *mtd)
|
||||
static int atmel_nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
|
||||
return gpiod_get_value(nand->activecs->rb.gpio);
|
||||
}
|
||||
|
||||
static void atmel_nand_select_chip(struct mtd_info *mtd, int cs)
|
||||
static void atmel_nand_select_chip(struct nand_chip *chip, int cs)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
|
||||
if (cs < 0 || cs >= nand->numcs) {
|
||||
nand->activecs = NULL;
|
||||
chip->dev_ready = NULL;
|
||||
chip->legacy.dev_ready = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
nand->activecs = &nand->cs[cs];
|
||||
|
||||
if (nand->activecs->rb.type == ATMEL_NAND_GPIO_RB)
|
||||
chip->dev_ready = atmel_nand_dev_ready;
|
||||
chip->legacy.dev_ready = atmel_nand_dev_ready;
|
||||
}
|
||||
|
||||
static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
|
||||
static int atmel_hsmc_nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
struct atmel_hsmc_nand_controller *nc;
|
||||
u32 status;
|
||||
|
@ -526,15 +511,15 @@ static int atmel_hsmc_nand_dev_ready(struct mtd_info *mtd)
|
|||
return status & ATMEL_HSMC_NFC_SR_RBEDGE(nand->activecs->rb.id);
|
||||
}
|
||||
|
||||
static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
|
||||
static void atmel_hsmc_nand_select_chip(struct nand_chip *chip, int cs)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
struct atmel_hsmc_nand_controller *nc;
|
||||
|
||||
nc = to_hsmc_nand_controller(chip->controller);
|
||||
|
||||
atmel_nand_select_chip(mtd, cs);
|
||||
atmel_nand_select_chip(chip, cs);
|
||||
|
||||
if (!nand->activecs) {
|
||||
regmap_write(nc->base.smc, ATMEL_HSMC_NFC_CTRL,
|
||||
|
@ -543,7 +528,7 @@ static void atmel_hsmc_nand_select_chip(struct mtd_info *mtd, int cs)
|
|||
}
|
||||
|
||||
if (nand->activecs->rb.type == ATMEL_NAND_NATIVE_RB)
|
||||
chip->dev_ready = atmel_hsmc_nand_dev_ready;
|
||||
chip->legacy.dev_ready = atmel_hsmc_nand_dev_ready;
|
||||
|
||||
regmap_update_bits(nc->base.smc, ATMEL_HSMC_NFC_CFG,
|
||||
ATMEL_HSMC_NFC_CFG_PAGESIZE_MASK |
|
||||
|
@ -607,10 +592,9 @@ static int atmel_nfc_exec_op(struct atmel_hsmc_nand_controller *nc, bool poll)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
|
||||
static void atmel_hsmc_nand_cmd_ctrl(struct nand_chip *chip, int dat,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
struct atmel_hsmc_nand_controller *nc;
|
||||
|
||||
|
@ -634,10 +618,9 @@ static void atmel_hsmc_nand_cmd_ctrl(struct mtd_info *mtd, int dat,
|
|||
}
|
||||
}
|
||||
|
||||
static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
static void atmel_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
struct atmel_nand_controller *nc;
|
||||
|
||||
|
@ -851,7 +834,7 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
atmel_nand_write_buf(mtd, buf, mtd->writesize);
|
||||
atmel_nand_write_buf(chip, buf, mtd->writesize);
|
||||
|
||||
ret = atmel_nand_pmecc_generate_eccbytes(chip, raw);
|
||||
if (ret) {
|
||||
|
@ -861,20 +844,18 @@ static int atmel_nand_pmecc_write_pg(struct nand_chip *chip, const u8 *buf,
|
|||
|
||||
atmel_nand_pmecc_disable(chip, raw);
|
||||
|
||||
atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
atmel_nand_write_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const u8 *buf,
|
||||
static int atmel_nand_pmecc_write_page(struct nand_chip *chip, const u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
return atmel_nand_pmecc_write_pg(chip, buf, oob_required, page, false);
|
||||
}
|
||||
|
||||
static int atmel_nand_pmecc_write_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int atmel_nand_pmecc_write_page_raw(struct nand_chip *chip,
|
||||
const u8 *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
|
@ -893,8 +874,8 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
atmel_nand_read_buf(mtd, buf, mtd->writesize);
|
||||
atmel_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
atmel_nand_read_buf(chip, buf, mtd->writesize);
|
||||
atmel_nand_read_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
ret = atmel_nand_pmecc_correct_data(chip, buf, raw);
|
||||
|
||||
|
@ -903,15 +884,13 @@ static int atmel_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u8 *buf,
|
||||
static int atmel_nand_pmecc_read_page(struct nand_chip *chip, u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, false);
|
||||
}
|
||||
|
||||
static int atmel_nand_pmecc_read_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u8 *buf,
|
||||
static int atmel_nand_pmecc_read_page_raw(struct nand_chip *chip, u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
return atmel_nand_pmecc_read_pg(chip, buf, oob_required, page, true);
|
||||
|
@ -956,7 +935,7 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
atmel_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
atmel_nand_write_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
nc->op.cmds[0] = NAND_CMD_PAGEPROG;
|
||||
nc->op.ncmds = 1;
|
||||
|
@ -966,15 +945,14 @@ static int atmel_hsmc_nand_pmecc_write_pg(struct nand_chip *chip,
|
|||
dev_err(nc->base.dev, "Failed to program NAND page (err = %d)\n",
|
||||
ret);
|
||||
|
||||
status = chip->waitfunc(mtd, chip);
|
||||
status = chip->legacy.waitfunc(chip);
|
||||
if (status & NAND_STATUS_FAIL)
|
||||
return -EIO;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int atmel_hsmc_nand_pmecc_write_page(struct nand_chip *chip,
|
||||
const u8 *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
|
@ -982,8 +960,7 @@ static int atmel_hsmc_nand_pmecc_write_page(struct mtd_info *mtd,
|
|||
false);
|
||||
}
|
||||
|
||||
static int atmel_hsmc_nand_pmecc_write_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int atmel_hsmc_nand_pmecc_write_page_raw(struct nand_chip *chip,
|
||||
const u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
|
@ -1045,16 +1022,14 @@ static int atmel_hsmc_nand_pmecc_read_pg(struct nand_chip *chip, u8 *buf,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_hsmc_nand_pmecc_read_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u8 *buf,
|
||||
static int atmel_hsmc_nand_pmecc_read_page(struct nand_chip *chip, u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
return atmel_hsmc_nand_pmecc_read_pg(chip, buf, oob_required, page,
|
||||
false);
|
||||
}
|
||||
|
||||
static int atmel_hsmc_nand_pmecc_read_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int atmel_hsmc_nand_pmecc_read_page_raw(struct nand_chip *chip,
|
||||
u8 *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
|
@ -1473,10 +1448,9 @@ static int atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline,
|
||||
static int atmel_nand_setup_data_interface(struct nand_chip *chip, int csline,
|
||||
const struct nand_data_interface *conf)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct atmel_nand *nand = to_atmel_nand(chip);
|
||||
struct atmel_nand_controller *nc;
|
||||
|
||||
|
@ -1498,19 +1472,18 @@ static void atmel_nand_init(struct atmel_nand_controller *nc,
|
|||
mtd->dev.parent = nc->dev;
|
||||
nand->base.controller = &nc->base;
|
||||
|
||||
chip->cmd_ctrl = atmel_nand_cmd_ctrl;
|
||||
chip->read_byte = atmel_nand_read_byte;
|
||||
chip->read_word = atmel_nand_read_word;
|
||||
chip->write_byte = atmel_nand_write_byte;
|
||||
chip->read_buf = atmel_nand_read_buf;
|
||||
chip->write_buf = atmel_nand_write_buf;
|
||||
chip->legacy.cmd_ctrl = atmel_nand_cmd_ctrl;
|
||||
chip->legacy.read_byte = atmel_nand_read_byte;
|
||||
chip->legacy.write_byte = atmel_nand_write_byte;
|
||||
chip->legacy.read_buf = atmel_nand_read_buf;
|
||||
chip->legacy.write_buf = atmel_nand_write_buf;
|
||||
chip->select_chip = atmel_nand_select_chip;
|
||||
|
||||
if (nc->mck && nc->caps->ops->setup_data_interface)
|
||||
chip->setup_data_interface = atmel_nand_setup_data_interface;
|
||||
|
||||
/* Some NANDs require a longer delay than the default one (20us). */
|
||||
chip->chip_delay = 40;
|
||||
chip->legacy.chip_delay = 40;
|
||||
|
||||
/*
|
||||
* Use a bounce buffer when the buffer passed by the MTD user is not
|
||||
|
@ -1551,7 +1524,7 @@ static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc,
|
|||
atmel_nand_init(nc, nand);
|
||||
|
||||
/* Overload some methods for the HSMC controller. */
|
||||
chip->cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
|
||||
chip->legacy.cmd_ctrl = atmel_hsmc_nand_cmd_ctrl;
|
||||
chip->select_chip = atmel_hsmc_nand_select_chip;
|
||||
}
|
||||
|
||||
|
@ -1586,9 +1559,7 @@ static struct atmel_nand *atmel_nand_create(struct atmel_nand_controller *nc,
|
|||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
nand = devm_kzalloc(nc->dev,
|
||||
sizeof(*nand) + (numcs * sizeof(*nand->cs)),
|
||||
GFP_KERNEL);
|
||||
nand = devm_kzalloc(nc->dev, struct_size(nand, cs, numcs), GFP_KERNEL);
|
||||
if (!nand) {
|
||||
dev_err(nc->dev, "Failed to allocate NAND object\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
@ -1694,7 +1665,7 @@ atmel_nand_controller_add_nand(struct atmel_nand_controller *nc,
|
|||
|
||||
nc->caps->ops->nand_init(nc, nand);
|
||||
|
||||
ret = nand_scan(mtd, nand->numcs);
|
||||
ret = nand_scan(chip, nand->numcs);
|
||||
if (ret) {
|
||||
dev_err(nc->dev, "NAND scan failed: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -2063,6 +2034,10 @@ atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc)
|
|||
nand_np = dev->of_node;
|
||||
nfc_np = of_find_compatible_node(dev->of_node, NULL,
|
||||
"atmel,sama5d3-nfc");
|
||||
if (!nfc_np) {
|
||||
dev_err(dev, "Could not find device node for sama5d3-nfc\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
nc->clk = of_clk_get(nfc_np, 0);
|
||||
if (IS_ERR(nc->clk)) {
|
||||
|
|
|
@ -24,134 +24,113 @@ struct au1550nd_ctx {
|
|||
|
||||
int cs;
|
||||
void __iomem *base;
|
||||
void (*write_byte)(struct mtd_info *, u_char);
|
||||
void (*write_byte)(struct nand_chip *, u_char);
|
||||
};
|
||||
|
||||
/**
|
||||
* au_read_byte - read one byte from the chip
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
*
|
||||
* read function for 8bit buswidth
|
||||
*/
|
||||
static u_char au_read_byte(struct mtd_info *mtd)
|
||||
static u_char au_read_byte(struct nand_chip *this)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
u_char ret = readb(this->IO_ADDR_R);
|
||||
u_char ret = readb(this->legacy.IO_ADDR_R);
|
||||
wmb(); /* drain writebuffer */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* au_write_byte - write one byte to the chip
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
* @byte: pointer to data byte to write
|
||||
*
|
||||
* write function for 8it buswidth
|
||||
*/
|
||||
static void au_write_byte(struct mtd_info *mtd, u_char byte)
|
||||
static void au_write_byte(struct nand_chip *this, u_char byte)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
writeb(byte, this->IO_ADDR_W);
|
||||
writeb(byte, this->legacy.IO_ADDR_W);
|
||||
wmb(); /* drain writebuffer */
|
||||
}
|
||||
|
||||
/**
|
||||
* au_read_byte16 - read one byte endianness aware from the chip
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
*
|
||||
* read function for 16bit buswidth with endianness conversion
|
||||
*/
|
||||
static u_char au_read_byte16(struct mtd_info *mtd)
|
||||
static u_char au_read_byte16(struct nand_chip *this)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
|
||||
u_char ret = (u_char) cpu_to_le16(readw(this->legacy.IO_ADDR_R));
|
||||
wmb(); /* drain writebuffer */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* au_write_byte16 - write one byte endianness aware to the chip
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
* @byte: pointer to data byte to write
|
||||
*
|
||||
* write function for 16bit buswidth with endianness conversion
|
||||
*/
|
||||
static void au_write_byte16(struct mtd_info *mtd, u_char byte)
|
||||
static void au_write_byte16(struct nand_chip *this, u_char byte)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
|
||||
writew(le16_to_cpu((u16) byte), this->legacy.IO_ADDR_W);
|
||||
wmb(); /* drain writebuffer */
|
||||
}
|
||||
|
||||
/**
|
||||
* au_read_word - read one word from the chip
|
||||
* @mtd: MTD device structure
|
||||
*
|
||||
* read function for 16bit buswidth without endianness conversion
|
||||
*/
|
||||
static u16 au_read_word(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
u16 ret = readw(this->IO_ADDR_R);
|
||||
wmb(); /* drain writebuffer */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* au_write_buf - write buffer to chip
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
* @buf: data buffer
|
||||
* @len: number of bytes to write
|
||||
*
|
||||
* write function for 8bit buswidth
|
||||
*/
|
||||
static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
static void au_write_buf(struct nand_chip *this, const u_char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
writeb(buf[i], this->IO_ADDR_W);
|
||||
writeb(buf[i], this->legacy.IO_ADDR_W);
|
||||
wmb(); /* drain writebuffer */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* au_read_buf - read chip data into buffer
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
* @buf: buffer to store date
|
||||
* @len: number of bytes to read
|
||||
*
|
||||
* read function for 8bit buswidth
|
||||
*/
|
||||
static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void au_read_buf(struct nand_chip *this, u_char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
buf[i] = readb(this->IO_ADDR_R);
|
||||
buf[i] = readb(this->legacy.IO_ADDR_R);
|
||||
wmb(); /* drain writebuffer */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* au_write_buf16 - write buffer to chip
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
* @buf: data buffer
|
||||
* @len: number of bytes to write
|
||||
*
|
||||
* write function for 16bit buswidth
|
||||
*/
|
||||
static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
static void au_write_buf16(struct nand_chip *this, const u_char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
u16 *p = (u16 *) buf;
|
||||
len >>= 1;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
writew(p[i], this->IO_ADDR_W);
|
||||
writew(p[i], this->legacy.IO_ADDR_W);
|
||||
wmb(); /* drain writebuffer */
|
||||
}
|
||||
|
||||
|
@ -173,7 +152,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
|
|||
len >>= 1;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
p[i] = readw(this->IO_ADDR_R);
|
||||
p[i] = readw(this->legacy.IO_ADDR_R);
|
||||
wmb(); /* drain writebuffer */
|
||||
}
|
||||
}
|
||||
|
@ -200,19 +179,19 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
|
|||
switch (cmd) {
|
||||
|
||||
case NAND_CTL_SETCLE:
|
||||
this->IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
|
||||
this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
|
||||
break;
|
||||
|
||||
case NAND_CTL_CLRCLE:
|
||||
this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
|
||||
this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
|
||||
break;
|
||||
|
||||
case NAND_CTL_SETALE:
|
||||
this->IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
|
||||
this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
|
||||
break;
|
||||
|
||||
case NAND_CTL_CLRALE:
|
||||
this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
|
||||
this->legacy.IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
|
||||
/* FIXME: Nobody knows why this is necessary,
|
||||
* but it works only that way */
|
||||
udelay(1);
|
||||
|
@ -229,12 +208,12 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
|
|||
break;
|
||||
}
|
||||
|
||||
this->IO_ADDR_R = this->IO_ADDR_W;
|
||||
this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W;
|
||||
|
||||
wmb(); /* Drain the writebuffer */
|
||||
}
|
||||
|
||||
int au1550_device_ready(struct mtd_info *mtd)
|
||||
int au1550_device_ready(struct nand_chip *this)
|
||||
{
|
||||
return (alchemy_rdsmem(AU1000_MEM_STSTAT) & 0x1) ? 1 : 0;
|
||||
}
|
||||
|
@ -248,23 +227,24 @@ int au1550_device_ready(struct mtd_info *mtd)
|
|||
* chip needs it to be asserted during chip not ready time but the NAND
|
||||
* controller keeps it released.
|
||||
*
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
* @chip: chipnumber to select, -1 for deselect
|
||||
*/
|
||||
static void au1550_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void au1550_select_chip(struct nand_chip *this, int chip)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* au1550_command - Send command to NAND device
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
* @command: the command to be sent
|
||||
* @column: the column address for this command, -1 if none
|
||||
* @page_addr: the page address for this command, -1 if none
|
||||
*/
|
||||
static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
|
||||
static void au1550_command(struct nand_chip *this, unsigned command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(this);
|
||||
struct au1550nd_ctx *ctx = container_of(this, struct au1550nd_ctx,
|
||||
chip);
|
||||
int ce_override = 0, i;
|
||||
|
@ -289,9 +269,9 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
|
|||
column -= 256;
|
||||
readcmd = NAND_CMD_READ1;
|
||||
}
|
||||
ctx->write_byte(mtd, readcmd);
|
||||
ctx->write_byte(this, readcmd);
|
||||
}
|
||||
ctx->write_byte(mtd, command);
|
||||
ctx->write_byte(this, command);
|
||||
|
||||
/* Set ALE and clear CLE to start address cycle */
|
||||
au1550_hwcontrol(mtd, NAND_CTL_CLRCLE);
|
||||
|
@ -305,10 +285,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
|
|||
if (this->options & NAND_BUSWIDTH_16 &&
|
||||
!nand_opcode_8bits(command))
|
||||
column >>= 1;
|
||||
ctx->write_byte(mtd, column);
|
||||
ctx->write_byte(this, column);
|
||||
}
|
||||
if (page_addr != -1) {
|
||||
ctx->write_byte(mtd, (u8)(page_addr & 0xff));
|
||||
ctx->write_byte(this, (u8)(page_addr & 0xff));
|
||||
|
||||
if (command == NAND_CMD_READ0 ||
|
||||
command == NAND_CMD_READ1 ||
|
||||
|
@ -326,10 +306,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
|
|||
au1550_hwcontrol(mtd, NAND_CTL_SETNCE);
|
||||
}
|
||||
|
||||
ctx->write_byte(mtd, (u8)(page_addr >> 8));
|
||||
ctx->write_byte(this, (u8)(page_addr >> 8));
|
||||
|
||||
if (this->options & NAND_ROW_ADDR_3)
|
||||
ctx->write_byte(mtd,
|
||||
ctx->write_byte(this,
|
||||
((page_addr >> 16) & 0x0f));
|
||||
}
|
||||
/* Latch in address */
|
||||
|
@ -362,7 +342,8 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
|
|||
/* Apply a short delay always to ensure that we do wait tWB. */
|
||||
ndelay(100);
|
||||
/* Wait for a chip to become ready... */
|
||||
for (i = this->chip_delay; !this->dev_ready(mtd) && i > 0; --i)
|
||||
for (i = this->legacy.chip_delay;
|
||||
!this->legacy.dev_ready(this) && i > 0; --i)
|
||||
udelay(1);
|
||||
|
||||
/* Release -CE and re-enable interrupts. */
|
||||
|
@ -373,7 +354,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
|
|||
/* Apply this short delay always to ensure that we do wait tWB. */
|
||||
ndelay(100);
|
||||
|
||||
while(!this->dev_ready(mtd));
|
||||
while(!this->legacy.dev_ready(this));
|
||||
}
|
||||
|
||||
static int find_nand_cs(unsigned long nand_base)
|
||||
|
@ -448,25 +429,24 @@ static int au1550nd_probe(struct platform_device *pdev)
|
|||
}
|
||||
ctx->cs = cs;
|
||||
|
||||
this->dev_ready = au1550_device_ready;
|
||||
this->legacy.dev_ready = au1550_device_ready;
|
||||
this->select_chip = au1550_select_chip;
|
||||
this->cmdfunc = au1550_command;
|
||||
this->legacy.cmdfunc = au1550_command;
|
||||
|
||||
/* 30 us command delay time */
|
||||
this->chip_delay = 30;
|
||||
this->legacy.chip_delay = 30;
|
||||
this->ecc.mode = NAND_ECC_SOFT;
|
||||
this->ecc.algo = NAND_ECC_HAMMING;
|
||||
|
||||
if (pd->devwidth)
|
||||
this->options |= NAND_BUSWIDTH_16;
|
||||
|
||||
this->read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
|
||||
this->legacy.read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
|
||||
ctx->write_byte = (pd->devwidth) ? au_write_byte16 : au_write_byte;
|
||||
this->read_word = au_read_word;
|
||||
this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
|
||||
this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
|
||||
this->legacy.write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
|
||||
this->legacy.read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
|
||||
|
||||
ret = nand_scan(mtd, 1);
|
||||
ret = nand_scan(this, 1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "NAND scan failed with %d\n", ret);
|
||||
goto out3;
|
||||
|
@ -492,7 +472,7 @@ static int au1550nd_remove(struct platform_device *pdev)
|
|||
struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
|
||||
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
nand_release(nand_to_mtd(&ctx->chip));
|
||||
nand_release(&ctx->chip);
|
||||
iounmap(ctx->base);
|
||||
release_mem_region(r->start, 0x1000);
|
||||
kfree(ctx);
|
||||
|
|
|
@ -65,7 +65,7 @@ static int bcm47xxnflash_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
|
||||
|
||||
nand_release(nand_to_mtd(&nflash->nand_chip));
|
||||
nand_release(&nflash->nand_chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -170,10 +170,9 @@ static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
|
|||
* NAND chip ops
|
||||
**************************************************/
|
||||
|
||||
static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl)
|
||||
static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct nand_chip *nand_chip,
|
||||
int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
|
||||
u32 code = 0;
|
||||
|
||||
|
@ -191,15 +190,14 @@ static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
|||
}
|
||||
|
||||
/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
|
||||
static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
|
||||
int chip)
|
||||
static void bcm47xxnflash_ops_bcm4706_select_chip(struct nand_chip *chip,
|
||||
int cs)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
|
||||
static int bcm47xxnflash_ops_bcm4706_dev_ready(struct nand_chip *nand_chip)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
|
||||
|
||||
return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
|
||||
|
@ -212,11 +210,11 @@ static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
|
|||
* registers of ChipCommon core. Hacking cmd_ctrl to understand and convert
|
||||
* standard commands would be much more complicated.
|
||||
*/
|
||||
static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
|
||||
static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct nand_chip *nand_chip,
|
||||
unsigned command, int column,
|
||||
int page_addr)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(nand_chip);
|
||||
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
|
||||
struct bcma_drv_cc *cc = b47n->cc;
|
||||
u32 ctlcode;
|
||||
|
@ -229,10 +227,10 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
|
|||
|
||||
switch (command) {
|
||||
case NAND_CMD_RESET:
|
||||
nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE);
|
||||
nand_chip->legacy.cmd_ctrl(nand_chip, command, NAND_CTRL_CLE);
|
||||
|
||||
ndelay(100);
|
||||
nand_wait_ready(mtd);
|
||||
nand_wait_ready(nand_chip);
|
||||
break;
|
||||
case NAND_CMD_READID:
|
||||
ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
|
||||
|
@ -310,9 +308,9 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
|
|||
b47n->curr_command = command;
|
||||
}
|
||||
|
||||
static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
|
||||
static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct nand_chip *nand_chip)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(nand_chip);
|
||||
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
|
||||
struct bcma_drv_cc *cc = b47n->cc;
|
||||
u32 tmp = 0;
|
||||
|
@ -338,31 +336,31 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
|
||||
static void bcm47xxnflash_ops_bcm4706_read_buf(struct nand_chip *nand_chip,
|
||||
uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
|
||||
|
||||
switch (b47n->curr_command) {
|
||||
case NAND_CMD_READ0:
|
||||
case NAND_CMD_READOOB:
|
||||
bcm47xxnflash_ops_bcm4706_read(mtd, buf, len);
|
||||
bcm47xxnflash_ops_bcm4706_read(nand_to_mtd(nand_chip), buf,
|
||||
len);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command);
|
||||
}
|
||||
|
||||
static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
|
||||
static void bcm47xxnflash_ops_bcm4706_write_buf(struct nand_chip *nand_chip,
|
||||
const uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct bcm47xxnflash *b47n = nand_get_controller_data(nand_chip);
|
||||
|
||||
switch (b47n->curr_command) {
|
||||
case NAND_CMD_SEQIN:
|
||||
bcm47xxnflash_ops_bcm4706_write(mtd, buf, len);
|
||||
bcm47xxnflash_ops_bcm4706_write(nand_to_mtd(nand_chip), buf,
|
||||
len);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -386,16 +384,16 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
|
|||
u32 val;
|
||||
|
||||
b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
|
||||
nand_chip->cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
|
||||
nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
|
||||
b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
|
||||
b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
|
||||
b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
|
||||
b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
|
||||
b47n->nand_chip.set_features = nand_get_set_features_notsupp;
|
||||
b47n->nand_chip.get_features = nand_get_set_features_notsupp;
|
||||
nand_chip->legacy.cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
|
||||
nand_chip->legacy.dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
|
||||
b47n->nand_chip.legacy.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
|
||||
b47n->nand_chip.legacy.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
|
||||
b47n->nand_chip.legacy.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
|
||||
b47n->nand_chip.legacy.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
|
||||
b47n->nand_chip.legacy.set_features = nand_get_set_features_notsupp;
|
||||
b47n->nand_chip.legacy.get_features = nand_get_set_features_notsupp;
|
||||
|
||||
nand_chip->chip_delay = 50;
|
||||
nand_chip->legacy.chip_delay = 50;
|
||||
b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
|
||||
b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
|
||||
|
||||
|
@ -423,7 +421,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
|
|||
(w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
|
||||
|
||||
/* Scan NAND */
|
||||
err = nand_scan(nand_to_mtd(&b47n->nand_chip), 1);
|
||||
err = nand_scan(&b47n->nand_chip, 1);
|
||||
if (err) {
|
||||
pr_err("Could not scan NAND flash: %d\n", err);
|
||||
goto exit;
|
||||
|
|
|
@ -1231,15 +1231,14 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
|
|||
* NAND MTD API: read/program/erase
|
||||
***********************************************************************/
|
||||
|
||||
static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat,
|
||||
static void brcmnand_cmd_ctrl(struct nand_chip *chip, int dat,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
/* intentionally left blank */
|
||||
}
|
||||
|
||||
static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
|
||||
static int brcmnand_waitfunc(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||
struct brcmnand_controller *ctrl = host->ctrl;
|
||||
unsigned long timeo = msecs_to_jiffies(100);
|
||||
|
@ -1274,7 +1273,6 @@ static int brcmnand_low_level_op(struct brcmnand_host *host,
|
|||
enum brcmnand_llop_type type, u32 data,
|
||||
bool last_op)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(&host->chip);
|
||||
struct nand_chip *chip = &host->chip;
|
||||
struct brcmnand_controller *ctrl = host->ctrl;
|
||||
u32 tmp;
|
||||
|
@ -1307,13 +1305,13 @@ static int brcmnand_low_level_op(struct brcmnand_host *host,
|
|||
(void)brcmnand_read_reg(ctrl, BRCMNAND_LL_OP);
|
||||
|
||||
brcmnand_send_cmd(host, CMD_LOW_LEVEL_OP);
|
||||
return brcmnand_waitfunc(mtd, chip);
|
||||
return brcmnand_waitfunc(chip);
|
||||
}
|
||||
|
||||
static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
|
||||
static void brcmnand_cmdfunc(struct nand_chip *chip, unsigned command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||
struct brcmnand_controller *ctrl = host->ctrl;
|
||||
u64 addr = (u64)page_addr << chip->page_shift;
|
||||
|
@ -1383,7 +1381,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
|
|||
(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
|
||||
|
||||
brcmnand_send_cmd(host, native_cmd);
|
||||
brcmnand_waitfunc(mtd, chip);
|
||||
brcmnand_waitfunc(chip);
|
||||
|
||||
if (native_cmd == CMD_PARAMETER_READ ||
|
||||
native_cmd == CMD_PARAMETER_CHANGE_COL) {
|
||||
|
@ -1417,9 +1415,8 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
|
|||
brcmnand_wp(mtd, 1);
|
||||
}
|
||||
|
||||
static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t brcmnand_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||
struct brcmnand_controller *ctrl = host->ctrl;
|
||||
uint8_t ret = 0;
|
||||
|
@ -1474,19 +1471,18 @@ static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void brcmnand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void brcmnand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++, buf++)
|
||||
*buf = brcmnand_read_byte(mtd);
|
||||
*buf = brcmnand_read_byte(chip);
|
||||
}
|
||||
|
||||
static void brcmnand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
|
||||
static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||
|
||||
switch (host->last_cmd) {
|
||||
|
@ -1617,7 +1613,7 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
|
||||
/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
|
||||
brcmnand_send_cmd(host, CMD_PAGE_READ);
|
||||
brcmnand_waitfunc(mtd, chip);
|
||||
brcmnand_waitfunc(chip);
|
||||
|
||||
if (likely(buf)) {
|
||||
brcmnand_soc_data_bus_prepare(ctrl->soc, false);
|
||||
|
@ -1689,7 +1685,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
|
|||
sas = mtd->oobsize / chip->ecc.steps;
|
||||
|
||||
/* read without ecc for verification */
|
||||
ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
|
||||
ret = chip->ecc.read_page_raw(chip, buf, true, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1786,9 +1782,10 @@ try_dmaread:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int brcmnand_read_page(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||
u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
|
||||
|
||||
|
@ -1798,10 +1795,11 @@ static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
|
||||
}
|
||||
|
||||
static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int brcmnand_read_page_raw(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
|
||||
int ret;
|
||||
|
||||
|
@ -1814,17 +1812,18 @@ static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int brcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int brcmnand_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
return brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
|
||||
mtd->writesize >> FC_SHIFT,
|
||||
NULL, (u8 *)chip->oob_poi);
|
||||
}
|
||||
|
||||
static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int brcmnand_read_oob_raw(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||
|
||||
brcmnand_set_ecc_enabled(host, 0);
|
||||
|
@ -1892,7 +1891,7 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
|
||||
/* we cannot use SPARE_AREA_PROGRAM when PARTIAL_PAGE_EN=0 */
|
||||
brcmnand_send_cmd(host, CMD_PROGRAM_PAGE);
|
||||
status = brcmnand_waitfunc(mtd, chip);
|
||||
status = brcmnand_waitfunc(chip);
|
||||
|
||||
if (status & NAND_STATUS_FAIL) {
|
||||
dev_info(ctrl->dev, "program failed at %llx\n",
|
||||
|
@ -1906,9 +1905,10 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
static int brcmnand_write_page(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||
void *oob = oob_required ? chip->oob_poi : NULL;
|
||||
|
||||
|
@ -1918,10 +1918,10 @@ static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
static int brcmnand_write_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf,
|
||||
static int brcmnand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||
void *oob = oob_required ? chip->oob_poi : NULL;
|
||||
|
||||
|
@ -1933,16 +1933,16 @@ static int brcmnand_write_page_raw(struct mtd_info *mtd,
|
|||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int brcmnand_write_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
return brcmnand_write(mtd, chip, (u64)page << chip->page_shift,
|
||||
NULL, chip->oob_poi);
|
||||
return brcmnand_write(nand_to_mtd(chip), chip,
|
||||
(u64)page << chip->page_shift, NULL,
|
||||
chip->oob_poi);
|
||||
}
|
||||
|
||||
static int brcmnand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int brcmnand_write_oob_raw(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||
int ret;
|
||||
|
||||
|
@ -2270,15 +2270,12 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
|
|||
mtd->owner = THIS_MODULE;
|
||||
mtd->dev.parent = &pdev->dev;
|
||||
|
||||
chip->IO_ADDR_R = (void __iomem *)0xdeadbeef;
|
||||
chip->IO_ADDR_W = (void __iomem *)0xdeadbeef;
|
||||
|
||||
chip->cmd_ctrl = brcmnand_cmd_ctrl;
|
||||
chip->cmdfunc = brcmnand_cmdfunc;
|
||||
chip->waitfunc = brcmnand_waitfunc;
|
||||
chip->read_byte = brcmnand_read_byte;
|
||||
chip->read_buf = brcmnand_read_buf;
|
||||
chip->write_buf = brcmnand_write_buf;
|
||||
chip->legacy.cmd_ctrl = brcmnand_cmd_ctrl;
|
||||
chip->legacy.cmdfunc = brcmnand_cmdfunc;
|
||||
chip->legacy.waitfunc = brcmnand_waitfunc;
|
||||
chip->legacy.read_byte = brcmnand_read_byte;
|
||||
chip->legacy.read_buf = brcmnand_read_buf;
|
||||
chip->legacy.write_buf = brcmnand_write_buf;
|
||||
|
||||
chip->ecc.mode = NAND_ECC_HW;
|
||||
chip->ecc.read_page = brcmnand_read_page;
|
||||
|
@ -2301,7 +2298,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn)
|
|||
nand_writereg(ctrl, cfg_offs,
|
||||
nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH);
|
||||
|
||||
ret = nand_scan(mtd, 1);
|
||||
ret = nand_scan(chip, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -2616,7 +2613,7 @@ int brcmnand_remove(struct platform_device *pdev)
|
|||
struct brcmnand_host *host;
|
||||
|
||||
list_for_each_entry(host, &ctrl->host_list, node)
|
||||
nand_release(nand_to_mtd(&host->chip));
|
||||
nand_release(&host->chip);
|
||||
|
||||
clk_disable_unprepare(ctrl->clk);
|
||||
|
||||
|
|
|
@ -100,9 +100,8 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
|
|||
#define cafe_readl(cafe, addr) readl((cafe)->mmio + CAFE_##addr)
|
||||
#define cafe_writel(cafe, datum, addr) writel(datum, (cafe)->mmio + CAFE_##addr)
|
||||
|
||||
static int cafe_device_ready(struct mtd_info *mtd)
|
||||
static int cafe_device_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct cafe_priv *cafe = nand_get_controller_data(chip);
|
||||
int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000);
|
||||
uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
|
||||
|
@ -117,9 +116,8 @@ static int cafe_device_ready(struct mtd_info *mtd)
|
|||
}
|
||||
|
||||
|
||||
static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
static void cafe_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct cafe_priv *cafe = nand_get_controller_data(chip);
|
||||
|
||||
if (cafe->usedma)
|
||||
|
@ -133,9 +131,8 @@ static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
|||
len, cafe->datalen);
|
||||
}
|
||||
|
||||
static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void cafe_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct cafe_priv *cafe = nand_get_controller_data(chip);
|
||||
|
||||
if (cafe->usedma)
|
||||
|
@ -148,22 +145,21 @@ static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
|||
cafe->datalen += len;
|
||||
}
|
||||
|
||||
static uint8_t cafe_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t cafe_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct cafe_priv *cafe = nand_get_controller_data(chip);
|
||||
uint8_t d;
|
||||
|
||||
cafe_read_buf(mtd, &d, 1);
|
||||
cafe_read_buf(chip, &d, 1);
|
||||
cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
|
||||
static void cafe_nand_cmdfunc(struct nand_chip *chip, unsigned command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct cafe_priv *cafe = nand_get_controller_data(chip);
|
||||
int adrbytes = 0;
|
||||
uint32_t ctl1;
|
||||
|
@ -313,13 +309,12 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
|
|||
cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
|
||||
return;
|
||||
}
|
||||
nand_wait_ready(mtd);
|
||||
nand_wait_ready(chip);
|
||||
cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
|
||||
}
|
||||
|
||||
static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
|
||||
static void cafe_select_chip(struct nand_chip *chip, int chipnr)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct cafe_priv *cafe = nand_get_controller_data(chip);
|
||||
|
||||
cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
|
||||
|
@ -346,17 +341,19 @@ static irqreturn_t cafe_nand_interrupt(int irq, void *id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int cafe_nand_write_oob(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, int page)
|
||||
static int cafe_nand_write_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
|
||||
mtd->oobsize);
|
||||
}
|
||||
|
||||
/* Don't use -- use nand_read_oob_std for now */
|
||||
static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int cafe_nand_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
|
||||
}
|
||||
/**
|
||||
|
@ -369,9 +366,10 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
* The hw generator calculates the error syndrome automatically. Therefore
|
||||
* we need a special oob layout and handling.
|
||||
*/
|
||||
static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int cafe_nand_read_page(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct cafe_priv *cafe = nand_get_controller_data(chip);
|
||||
unsigned int max_bitflips = 0;
|
||||
|
||||
|
@ -380,7 +378,7 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
cafe_readl(cafe, NAND_ECC_SYN01));
|
||||
|
||||
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
|
||||
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
|
||||
unsigned short syn[8], pat[4];
|
||||
|
@ -531,15 +529,15 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
|
|||
};
|
||||
|
||||
|
||||
static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int cafe_nand_write_page_lowlevel(struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct cafe_priv *cafe = nand_get_controller_data(chip);
|
||||
|
||||
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
|
||||
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
/* Set up ECC autogeneration */
|
||||
cafe->ctl2 |= (1<<30);
|
||||
|
@ -547,7 +545,7 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
|
|||
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 nand_chip *chip, loff_t ofs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -705,23 +703,23 @@ static int cafe_nand_probe(struct pci_dev *pdev,
|
|||
goto out_ior;
|
||||
}
|
||||
|
||||
cafe->nand.cmdfunc = cafe_nand_cmdfunc;
|
||||
cafe->nand.dev_ready = cafe_device_ready;
|
||||
cafe->nand.read_byte = cafe_read_byte;
|
||||
cafe->nand.read_buf = cafe_read_buf;
|
||||
cafe->nand.write_buf = cafe_write_buf;
|
||||
cafe->nand.legacy.cmdfunc = cafe_nand_cmdfunc;
|
||||
cafe->nand.legacy.dev_ready = cafe_device_ready;
|
||||
cafe->nand.legacy.read_byte = cafe_read_byte;
|
||||
cafe->nand.legacy.read_buf = cafe_read_buf;
|
||||
cafe->nand.legacy.write_buf = cafe_write_buf;
|
||||
cafe->nand.select_chip = cafe_select_chip;
|
||||
cafe->nand.set_features = nand_get_set_features_notsupp;
|
||||
cafe->nand.get_features = nand_get_set_features_notsupp;
|
||||
cafe->nand.legacy.set_features = nand_get_set_features_notsupp;
|
||||
cafe->nand.legacy.get_features = nand_get_set_features_notsupp;
|
||||
|
||||
cafe->nand.chip_delay = 0;
|
||||
cafe->nand.legacy.chip_delay = 0;
|
||||
|
||||
/* Enable the following for a flash based bad block table */
|
||||
cafe->nand.bbt_options = NAND_BBT_USE_FLASH;
|
||||
|
||||
if (skipbbt) {
|
||||
cafe->nand.options |= NAND_SKIP_BBTSCAN;
|
||||
cafe->nand.block_bad = cafe_nand_block_bad;
|
||||
cafe->nand.legacy.block_bad = cafe_nand_block_bad;
|
||||
}
|
||||
|
||||
if (numtimings && numtimings != 3) {
|
||||
|
@ -783,7 +781,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
|
|||
|
||||
/* Scan to find existence of the device */
|
||||
cafe->nand.dummy_controller.ops = &cafe_nand_controller_ops;
|
||||
err = nand_scan(mtd, 2);
|
||||
err = nand_scan(&cafe->nand, 2);
|
||||
if (err)
|
||||
goto out_irq;
|
||||
|
||||
|
@ -819,7 +817,7 @@ static void cafe_nand_remove(struct pci_dev *pdev)
|
|||
/* Disable NAND IRQ in global IRQ mask register */
|
||||
cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
|
||||
free_irq(pdev->irq, mtd);
|
||||
nand_release(mtd);
|
||||
nand_release(chip);
|
||||
free_rs(cafe->rs);
|
||||
pci_iounmap(pdev, cafe->mmio);
|
||||
dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
|
||||
|
|
|
@ -49,29 +49,26 @@ static const struct mtd_partition partition_info[] = {
|
|||
};
|
||||
#define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
|
||||
|
||||
static u_char cmx270_read_byte(struct mtd_info *mtd)
|
||||
static u_char cmx270_read_byte(struct nand_chip *this)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
return (readl(this->IO_ADDR_R) >> 16);
|
||||
return (readl(this->legacy.IO_ADDR_R) >> 16);
|
||||
}
|
||||
|
||||
static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
static void cmx270_write_buf(struct nand_chip *this, const u_char *buf,
|
||||
int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
for (i=0; i<len; i++)
|
||||
writel((*buf++ << 16), this->IO_ADDR_W);
|
||||
writel((*buf++ << 16), this->legacy.IO_ADDR_W);
|
||||
}
|
||||
|
||||
static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void cmx270_read_buf(struct nand_chip *this, u_char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
for (i=0; i<len; i++)
|
||||
*buf++ = readl(this->IO_ADDR_R) >> 16;
|
||||
*buf++ = readl(this->legacy.IO_ADDR_R) >> 16;
|
||||
}
|
||||
|
||||
static inline void nand_cs_on(void)
|
||||
|
@ -89,11 +86,10 @@ static void nand_cs_off(void)
|
|||
/*
|
||||
* hardware specific access to control-lines
|
||||
*/
|
||||
static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
|
||||
static void cmx270_hwcontrol(struct nand_chip *this, int dat,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
|
||||
unsigned int nandaddr = (unsigned int)this->legacy.IO_ADDR_W;
|
||||
|
||||
dsb();
|
||||
|
||||
|
@ -113,9 +109,9 @@ static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
|
|||
}
|
||||
|
||||
dsb();
|
||||
this->IO_ADDR_W = (void __iomem*)nandaddr;
|
||||
this->legacy.IO_ADDR_W = (void __iomem*)nandaddr;
|
||||
if (dat != NAND_CMD_NONE)
|
||||
writel((dat << 16), this->IO_ADDR_W);
|
||||
writel((dat << 16), this->legacy.IO_ADDR_W);
|
||||
|
||||
dsb();
|
||||
}
|
||||
|
@ -123,7 +119,7 @@ static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
|
|||
/*
|
||||
* read device ready pin
|
||||
*/
|
||||
static int cmx270_device_ready(struct mtd_info *mtd)
|
||||
static int cmx270_device_ready(struct nand_chip *this)
|
||||
{
|
||||
dsb();
|
||||
|
||||
|
@ -177,23 +173,23 @@ static int __init cmx270_init(void)
|
|||
cmx270_nand_mtd->owner = THIS_MODULE;
|
||||
|
||||
/* insert callbacks */
|
||||
this->IO_ADDR_R = cmx270_nand_io;
|
||||
this->IO_ADDR_W = cmx270_nand_io;
|
||||
this->cmd_ctrl = cmx270_hwcontrol;
|
||||
this->dev_ready = cmx270_device_ready;
|
||||
this->legacy.IO_ADDR_R = cmx270_nand_io;
|
||||
this->legacy.IO_ADDR_W = cmx270_nand_io;
|
||||
this->legacy.cmd_ctrl = cmx270_hwcontrol;
|
||||
this->legacy.dev_ready = cmx270_device_ready;
|
||||
|
||||
/* 15 us command delay time */
|
||||
this->chip_delay = 20;
|
||||
this->legacy.chip_delay = 20;
|
||||
this->ecc.mode = NAND_ECC_SOFT;
|
||||
this->ecc.algo = NAND_ECC_HAMMING;
|
||||
|
||||
/* read/write functions */
|
||||
this->read_byte = cmx270_read_byte;
|
||||
this->read_buf = cmx270_read_buf;
|
||||
this->write_buf = cmx270_write_buf;
|
||||
this->legacy.read_byte = cmx270_read_byte;
|
||||
this->legacy.read_buf = cmx270_read_buf;
|
||||
this->legacy.write_buf = cmx270_write_buf;
|
||||
|
||||
/* Scan to find existence of the device */
|
||||
ret = nand_scan(cmx270_nand_mtd, 1);
|
||||
ret = nand_scan(this, 1);
|
||||
if (ret) {
|
||||
pr_notice("No NAND device\n");
|
||||
goto err_scan;
|
||||
|
@ -228,7 +224,7 @@ module_init(cmx270_init);
|
|||
static void __exit cmx270_cleanup(void)
|
||||
{
|
||||
/* Release resources, unregister device */
|
||||
nand_release(cmx270_nand_mtd);
|
||||
nand_release(mtd_to_nand(cmx270_nand_mtd));
|
||||
|
||||
gpio_free(GPIO_NAND_RB);
|
||||
gpio_free(GPIO_NAND_CS);
|
||||
|
|
|
@ -93,83 +93,74 @@
|
|||
#define CS_NAND_ECC_CLRECC (1<<1)
|
||||
#define CS_NAND_ECC_ENECC (1<<0)
|
||||
|
||||
static void cs553x_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void cs553x_read_buf(struct nand_chip *this, u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
while (unlikely(len > 0x800)) {
|
||||
memcpy_fromio(buf, this->IO_ADDR_R, 0x800);
|
||||
memcpy_fromio(buf, this->legacy.IO_ADDR_R, 0x800);
|
||||
buf += 0x800;
|
||||
len -= 0x800;
|
||||
}
|
||||
memcpy_fromio(buf, this->IO_ADDR_R, len);
|
||||
memcpy_fromio(buf, this->legacy.IO_ADDR_R, len);
|
||||
}
|
||||
|
||||
static void cs553x_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
static void cs553x_write_buf(struct nand_chip *this, const u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
|
||||
while (unlikely(len > 0x800)) {
|
||||
memcpy_toio(this->IO_ADDR_R, buf, 0x800);
|
||||
memcpy_toio(this->legacy.IO_ADDR_R, buf, 0x800);
|
||||
buf += 0x800;
|
||||
len -= 0x800;
|
||||
}
|
||||
memcpy_toio(this->IO_ADDR_R, buf, len);
|
||||
memcpy_toio(this->legacy.IO_ADDR_R, buf, len);
|
||||
}
|
||||
|
||||
static unsigned char cs553x_read_byte(struct mtd_info *mtd)
|
||||
static unsigned char cs553x_read_byte(struct nand_chip *this)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
return readb(this->IO_ADDR_R);
|
||||
return readb(this->legacy.IO_ADDR_R);
|
||||
}
|
||||
|
||||
static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
|
||||
static void cs553x_write_byte(struct nand_chip *this, u_char byte)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int i = 100000;
|
||||
|
||||
while (i && readb(this->IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
|
||||
while (i && readb(this->legacy.IO_ADDR_R + MM_NAND_STS) & CS_NAND_CTLR_BUSY) {
|
||||
udelay(1);
|
||||
i--;
|
||||
}
|
||||
writeb(byte, this->IO_ADDR_W + 0x801);
|
||||
writeb(byte, this->legacy.IO_ADDR_W + 0x801);
|
||||
}
|
||||
|
||||
static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
static void cs553x_hwcontrol(struct nand_chip *this, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
void __iomem *mmio_base = this->IO_ADDR_R;
|
||||
void __iomem *mmio_base = this->legacy.IO_ADDR_R;
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
|
||||
writeb(ctl, mmio_base + MM_NAND_CTL);
|
||||
}
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
cs553x_write_byte(mtd, cmd);
|
||||
cs553x_write_byte(this, cmd);
|
||||
}
|
||||
|
||||
static int cs553x_device_ready(struct mtd_info *mtd)
|
||||
static int cs553x_device_ready(struct nand_chip *this)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
void __iomem *mmio_base = this->IO_ADDR_R;
|
||||
void __iomem *mmio_base = this->legacy.IO_ADDR_R;
|
||||
unsigned char foo = readb(mmio_base + MM_NAND_STS);
|
||||
|
||||
return (foo & CS_NAND_STS_FLASH_RDY) && !(foo & CS_NAND_CTLR_BUSY);
|
||||
}
|
||||
|
||||
static void cs_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
static void cs_enable_hwecc(struct nand_chip *this, int mode)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
void __iomem *mmio_base = this->IO_ADDR_R;
|
||||
void __iomem *mmio_base = this->legacy.IO_ADDR_R;
|
||||
|
||||
writeb(0x07, mmio_base + MM_NAND_ECC_CTL);
|
||||
}
|
||||
|
||||
static int cs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
|
||||
static int cs_calculate_ecc(struct nand_chip *this, const u_char *dat,
|
||||
u_char *ecc_code)
|
||||
{
|
||||
uint32_t ecc;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
void __iomem *mmio_base = this->IO_ADDR_R;
|
||||
void __iomem *mmio_base = this->legacy.IO_ADDR_R;
|
||||
|
||||
ecc = readl(mmio_base + MM_NAND_STS);
|
||||
|
||||
|
@ -208,20 +199,20 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
|
|||
new_mtd->owner = THIS_MODULE;
|
||||
|
||||
/* map physical address */
|
||||
this->IO_ADDR_R = this->IO_ADDR_W = ioremap(adr, 4096);
|
||||
if (!this->IO_ADDR_R) {
|
||||
this->legacy.IO_ADDR_R = this->legacy.IO_ADDR_W = ioremap(adr, 4096);
|
||||
if (!this->legacy.IO_ADDR_R) {
|
||||
pr_warn("ioremap cs553x NAND @0x%08lx failed\n", adr);
|
||||
err = -EIO;
|
||||
goto out_mtd;
|
||||
}
|
||||
|
||||
this->cmd_ctrl = cs553x_hwcontrol;
|
||||
this->dev_ready = cs553x_device_ready;
|
||||
this->read_byte = cs553x_read_byte;
|
||||
this->read_buf = cs553x_read_buf;
|
||||
this->write_buf = cs553x_write_buf;
|
||||
this->legacy.cmd_ctrl = cs553x_hwcontrol;
|
||||
this->legacy.dev_ready = cs553x_device_ready;
|
||||
this->legacy.read_byte = cs553x_read_byte;
|
||||
this->legacy.read_buf = cs553x_read_buf;
|
||||
this->legacy.write_buf = cs553x_write_buf;
|
||||
|
||||
this->chip_delay = 0;
|
||||
this->legacy.chip_delay = 0;
|
||||
|
||||
this->ecc.mode = NAND_ECC_HW;
|
||||
this->ecc.size = 256;
|
||||
|
@ -241,7 +232,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
|
|||
}
|
||||
|
||||
/* Scan to find existence of the device */
|
||||
err = nand_scan(new_mtd, 1);
|
||||
err = nand_scan(this, 1);
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
|
@ -251,7 +242,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
|
|||
out_free:
|
||||
kfree(new_mtd->name);
|
||||
out_ior:
|
||||
iounmap(this->IO_ADDR_R);
|
||||
iounmap(this->legacy.IO_ADDR_R);
|
||||
out_mtd:
|
||||
kfree(this);
|
||||
out:
|
||||
|
@ -333,10 +324,10 @@ static void __exit cs553x_cleanup(void)
|
|||
continue;
|
||||
|
||||
this = mtd_to_nand(mtd);
|
||||
mmio_base = this->IO_ADDR_R;
|
||||
mmio_base = this->legacy.IO_ADDR_R;
|
||||
|
||||
/* Release resources, unregister device */
|
||||
nand_release(mtd);
|
||||
nand_release(this);
|
||||
kfree(mtd->name);
|
||||
cs553x_mtd[i] = NULL;
|
||||
|
||||
|
|
|
@ -97,12 +97,11 @@ static inline void davinci_nand_writel(struct davinci_nand_info *info,
|
|||
* Access to hardware control lines: ALE, CLE, secondary chipselect.
|
||||
*/
|
||||
|
||||
static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
static void nand_davinci_hwcontrol(struct nand_chip *nand, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct davinci_nand_info *info = to_davinci_nand(mtd);
|
||||
struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(nand));
|
||||
void __iomem *addr = info->current_cs;
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
|
||||
/* Did the control lines change? */
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
|
@ -111,16 +110,16 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd,
|
|||
else if ((ctrl & NAND_CTRL_ALE) == NAND_CTRL_ALE)
|
||||
addr += info->mask_ale;
|
||||
|
||||
nand->IO_ADDR_W = addr;
|
||||
nand->legacy.IO_ADDR_W = addr;
|
||||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
iowrite8(cmd, nand->IO_ADDR_W);
|
||||
iowrite8(cmd, nand->legacy.IO_ADDR_W);
|
||||
}
|
||||
|
||||
static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void nand_davinci_select_chip(struct nand_chip *nand, int chip)
|
||||
{
|
||||
struct davinci_nand_info *info = to_davinci_nand(mtd);
|
||||
struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(nand));
|
||||
|
||||
info->current_cs = info->vaddr;
|
||||
|
||||
|
@ -128,8 +127,8 @@ static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
|
|||
if (chip > 0)
|
||||
info->current_cs += info->mask_chipsel;
|
||||
|
||||
info->chip.IO_ADDR_W = info->current_cs;
|
||||
info->chip.IO_ADDR_R = info->chip.IO_ADDR_W;
|
||||
info->chip.legacy.IO_ADDR_W = info->current_cs;
|
||||
info->chip.legacy.IO_ADDR_R = info->chip.legacy.IO_ADDR_W;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
@ -146,16 +145,16 @@ static inline uint32_t nand_davinci_readecc_1bit(struct mtd_info *mtd)
|
|||
+ 4 * info->core_chipsel);
|
||||
}
|
||||
|
||||
static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
|
||||
static void nand_davinci_hwctl_1bit(struct nand_chip *chip, int mode)
|
||||
{
|
||||
struct davinci_nand_info *info;
|
||||
uint32_t nandcfr;
|
||||
unsigned long flags;
|
||||
|
||||
info = to_davinci_nand(mtd);
|
||||
info = to_davinci_nand(nand_to_mtd(chip));
|
||||
|
||||
/* Reset ECC hardware */
|
||||
nand_davinci_readecc_1bit(mtd);
|
||||
nand_davinci_readecc_1bit(nand_to_mtd(chip));
|
||||
|
||||
spin_lock_irqsave(&davinci_nand_lock, flags);
|
||||
|
||||
|
@ -170,10 +169,10 @@ static void nand_davinci_hwctl_1bit(struct mtd_info *mtd, int mode)
|
|||
/*
|
||||
* Read hardware ECC value and pack into three bytes
|
||||
*/
|
||||
static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
|
||||
static int nand_davinci_calculate_1bit(struct nand_chip *chip,
|
||||
const u_char *dat, u_char *ecc_code)
|
||||
{
|
||||
unsigned int ecc_val = nand_davinci_readecc_1bit(mtd);
|
||||
unsigned int ecc_val = nand_davinci_readecc_1bit(nand_to_mtd(chip));
|
||||
unsigned int ecc24 = (ecc_val & 0x0fff) | ((ecc_val & 0x0fff0000) >> 4);
|
||||
|
||||
/* invert so that erased block ecc is correct */
|
||||
|
@ -185,10 +184,9 @@ static int nand_davinci_calculate_1bit(struct mtd_info *mtd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
|
||||
static int nand_davinci_correct_1bit(struct nand_chip *chip, u_char *dat,
|
||||
u_char *read_ecc, u_char *calc_ecc)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
uint32_t eccNand = read_ecc[0] | (read_ecc[1] << 8) |
|
||||
(read_ecc[2] << 16);
|
||||
uint32_t eccCalc = calc_ecc[0] | (calc_ecc[1] << 8) |
|
||||
|
@ -231,9 +229,9 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat,
|
|||
* OOB without recomputing ECC.
|
||||
*/
|
||||
|
||||
static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode)
|
||||
static void nand_davinci_hwctl_4bit(struct nand_chip *chip, int mode)
|
||||
{
|
||||
struct davinci_nand_info *info = to_davinci_nand(mtd);
|
||||
struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
|
@ -266,10 +264,10 @@ nand_davinci_readecc_4bit(struct davinci_nand_info *info, u32 code[4])
|
|||
}
|
||||
|
||||
/* Terminate read ECC; or return ECC (as bytes) of data written to NAND. */
|
||||
static int nand_davinci_calculate_4bit(struct mtd_info *mtd,
|
||||
static int nand_davinci_calculate_4bit(struct nand_chip *chip,
|
||||
const u_char *dat, u_char *ecc_code)
|
||||
{
|
||||
struct davinci_nand_info *info = to_davinci_nand(mtd);
|
||||
struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
|
||||
u32 raw_ecc[4], *p;
|
||||
unsigned i;
|
||||
|
||||
|
@ -303,11 +301,11 @@ static int nand_davinci_calculate_4bit(struct mtd_info *mtd,
|
|||
/* Correct up to 4 bits in data we just read, using state left in the
|
||||
* hardware plus the ecc_code computed when it was first written.
|
||||
*/
|
||||
static int nand_davinci_correct_4bit(struct mtd_info *mtd,
|
||||
u_char *data, u_char *ecc_code, u_char *null)
|
||||
static int nand_davinci_correct_4bit(struct nand_chip *chip, u_char *data,
|
||||
u_char *ecc_code, u_char *null)
|
||||
{
|
||||
int i;
|
||||
struct davinci_nand_info *info = to_davinci_nand(mtd);
|
||||
struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
|
||||
unsigned short ecc10[8];
|
||||
unsigned short *ecc16;
|
||||
u32 syndrome[4];
|
||||
|
@ -436,38 +434,35 @@ correct:
|
|||
* the two LSBs for NAND access ... so we can issue 32-bit reads/writes
|
||||
* and have that transparently morphed into multiple NAND operations.
|
||||
*/
|
||||
static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void nand_davinci_read_buf(struct nand_chip *chip, uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0)
|
||||
ioread32_rep(chip->IO_ADDR_R, buf, len >> 2);
|
||||
ioread32_rep(chip->legacy.IO_ADDR_R, buf, len >> 2);
|
||||
else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0)
|
||||
ioread16_rep(chip->IO_ADDR_R, buf, len >> 1);
|
||||
ioread16_rep(chip->legacy.IO_ADDR_R, buf, len >> 1);
|
||||
else
|
||||
ioread8_rep(chip->IO_ADDR_R, buf, len);
|
||||
ioread8_rep(chip->legacy.IO_ADDR_R, buf, len);
|
||||
}
|
||||
|
||||
static void nand_davinci_write_buf(struct mtd_info *mtd,
|
||||
const uint8_t *buf, int len)
|
||||
static void nand_davinci_write_buf(struct nand_chip *chip, const uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
if ((0x03 & ((uintptr_t)buf)) == 0 && (0x03 & len) == 0)
|
||||
iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
|
||||
iowrite32_rep(chip->legacy.IO_ADDR_R, buf, len >> 2);
|
||||
else if ((0x01 & ((uintptr_t)buf)) == 0 && (0x01 & len) == 0)
|
||||
iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);
|
||||
iowrite16_rep(chip->legacy.IO_ADDR_R, buf, len >> 1);
|
||||
else
|
||||
iowrite8_rep(chip->IO_ADDR_R, buf, len);
|
||||
iowrite8_rep(chip->legacy.IO_ADDR_R, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check hardware register for wait status. Returns 1 if device is ready,
|
||||
* 0 if it is still busy.
|
||||
*/
|
||||
static int nand_davinci_dev_ready(struct mtd_info *mtd)
|
||||
static int nand_davinci_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct davinci_nand_info *info = to_davinci_nand(mtd);
|
||||
struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
|
||||
|
||||
return davinci_nand_readl(info, NANDFSR_OFFSET) & BIT(0);
|
||||
}
|
||||
|
@ -764,9 +759,9 @@ static int nand_davinci_probe(struct platform_device *pdev)
|
|||
mtd->dev.parent = &pdev->dev;
|
||||
nand_set_flash_node(&info->chip, pdev->dev.of_node);
|
||||
|
||||
info->chip.IO_ADDR_R = vaddr;
|
||||
info->chip.IO_ADDR_W = vaddr;
|
||||
info->chip.chip_delay = 0;
|
||||
info->chip.legacy.IO_ADDR_R = vaddr;
|
||||
info->chip.legacy.IO_ADDR_W = vaddr;
|
||||
info->chip.legacy.chip_delay = 0;
|
||||
info->chip.select_chip = nand_davinci_select_chip;
|
||||
|
||||
/* options such as NAND_BBT_USE_FLASH */
|
||||
|
@ -786,12 +781,12 @@ static int nand_davinci_probe(struct platform_device *pdev)
|
|||
info->mask_cle = pdata->mask_cle ? : MASK_CLE;
|
||||
|
||||
/* Set address of hardware control function */
|
||||
info->chip.cmd_ctrl = nand_davinci_hwcontrol;
|
||||
info->chip.dev_ready = nand_davinci_dev_ready;
|
||||
info->chip.legacy.cmd_ctrl = nand_davinci_hwcontrol;
|
||||
info->chip.legacy.dev_ready = nand_davinci_dev_ready;
|
||||
|
||||
/* Speed up buffer I/O */
|
||||
info->chip.read_buf = nand_davinci_read_buf;
|
||||
info->chip.write_buf = nand_davinci_write_buf;
|
||||
info->chip.legacy.read_buf = nand_davinci_read_buf;
|
||||
info->chip.legacy.write_buf = nand_davinci_write_buf;
|
||||
|
||||
/* Use board-specific ECC config */
|
||||
info->chip.ecc.mode = pdata->ecc_mode;
|
||||
|
@ -807,7 +802,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
|
|||
|
||||
/* Scan to find existence of the device(s) */
|
||||
info->chip.dummy_controller.ops = &davinci_nand_controller_ops;
|
||||
ret = nand_scan(mtd, pdata->mask_chipsel ? 2 : 1);
|
||||
ret = nand_scan(&info->chip, pdata->mask_chipsel ? 2 : 1);
|
||||
if (ret < 0) {
|
||||
dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
|
||||
return ret;
|
||||
|
@ -841,7 +836,7 @@ static int nand_davinci_remove(struct platform_device *pdev)
|
|||
ecc4_busy = false;
|
||||
spin_unlock_irq(&davinci_nand_lock);
|
||||
|
||||
nand_release(nand_to_mtd(&info->chip));
|
||||
nand_release(&info->chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* NAND Flash Controller Device Driver
|
||||
* Copyright © 2009-2010, Intel Corporation and its suppliers.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
* Copyright (c) 2017 Socionext Inc.
|
||||
* Reworked by Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
|
@ -25,9 +20,8 @@
|
|||
|
||||
#include "denali.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define DENALI_NAND_NAME "denali-nand"
|
||||
#define DENALI_DEFAULT_OOB_SKIP_BYTES 8
|
||||
|
||||
/* for Indexed Addressing */
|
||||
#define DENALI_INDEXED_CTRL 0x00
|
||||
|
@ -222,8 +216,9 @@ static uint32_t denali_check_irq(struct denali_nand_info *denali)
|
|||
return irq_status;
|
||||
}
|
||||
|
||||
static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void denali_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
|
||||
int i;
|
||||
|
@ -232,9 +227,10 @@ static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
|||
buf[i] = denali->host_read(denali, addr);
|
||||
}
|
||||
|
||||
static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
static void denali_write_buf(struct nand_chip *chip, const uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
|
||||
u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
|
||||
int i;
|
||||
|
||||
|
@ -242,9 +238,9 @@ static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
|||
denali->host_write(denali, addr, buf[i]);
|
||||
}
|
||||
|
||||
static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void denali_read_buf16(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
|
||||
u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
|
||||
uint16_t *buf16 = (uint16_t *)buf;
|
||||
int i;
|
||||
|
@ -253,10 +249,10 @@ static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
|
|||
buf16[i] = denali->host_read(denali, addr);
|
||||
}
|
||||
|
||||
static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
|
||||
static void denali_write_buf16(struct nand_chip *chip, const uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
|
||||
u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
|
||||
const uint16_t *buf16 = (const uint16_t *)buf;
|
||||
int i;
|
||||
|
@ -265,32 +261,23 @@ static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
|
|||
denali->host_write(denali, addr, buf16[i]);
|
||||
}
|
||||
|
||||
static uint8_t denali_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t denali_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
uint8_t byte;
|
||||
|
||||
denali_read_buf(mtd, &byte, 1);
|
||||
denali_read_buf(chip, &byte, 1);
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
static void denali_write_byte(struct mtd_info *mtd, uint8_t byte)
|
||||
static void denali_write_byte(struct nand_chip *chip, uint8_t byte)
|
||||
{
|
||||
denali_write_buf(mtd, &byte, 1);
|
||||
denali_write_buf(chip, &byte, 1);
|
||||
}
|
||||
|
||||
static uint16_t denali_read_word(struct mtd_info *mtd)
|
||||
static void denali_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
|
||||
{
|
||||
uint16_t word;
|
||||
|
||||
denali_read_buf16(mtd, (uint8_t *)&word, 2);
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
|
||||
{
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
|
||||
uint32_t type;
|
||||
|
||||
if (ctrl & NAND_CLE)
|
||||
|
@ -301,7 +288,8 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
|
|||
return;
|
||||
|
||||
/*
|
||||
* Some commands are followed by chip->dev_ready or chip->waitfunc.
|
||||
* Some commands are followed by chip->legacy.dev_ready or
|
||||
* chip->legacy.waitfunc.
|
||||
* irq_status must be cleared here to catch the R/B# interrupt later.
|
||||
*/
|
||||
if (ctrl & NAND_CTRL_CHANGE)
|
||||
|
@ -310,9 +298,9 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
|
|||
denali->host_write(denali, DENALI_BANK(denali) | type, dat);
|
||||
}
|
||||
|
||||
static int denali_dev_ready(struct mtd_info *mtd)
|
||||
static int denali_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
|
||||
|
||||
return !!(denali_check_irq(denali) & INTR__INT_ACT);
|
||||
}
|
||||
|
@ -698,9 +686,10 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
false);
|
||||
}
|
||||
|
||||
static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int denali_read_page_raw(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
int writesize = mtd->writesize;
|
||||
int oobsize = mtd->oobsize;
|
||||
|
@ -773,17 +762,18 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int denali_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
denali_oob_xfer(mtd, chip, page, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int denali_write_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
|
||||
denali_reset_irq(denali);
|
||||
|
@ -793,9 +783,10 @@ static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int denali_read_page(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
unsigned long uncor_ecc_flags = 0;
|
||||
int stat = 0;
|
||||
|
@ -814,7 +805,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return stat;
|
||||
|
||||
if (uncor_ecc_flags) {
|
||||
ret = denali_read_oob(mtd, chip, page);
|
||||
ret = denali_read_oob(chip, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -825,9 +816,10 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return stat;
|
||||
}
|
||||
|
||||
static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
static int denali_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
int writesize = mtd->writesize;
|
||||
int oobsize = mtd->oobsize;
|
||||
|
@ -903,25 +895,26 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return denali_data_xfer(denali, tmp_buf, size, page, 1, 1);
|
||||
}
|
||||
|
||||
static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
static int denali_write_page(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
|
||||
return denali_data_xfer(denali, (void *)buf, mtd->writesize,
|
||||
page, 0, 1);
|
||||
}
|
||||
|
||||
static void denali_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void denali_select_chip(struct nand_chip *chip, int cs)
|
||||
{
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
|
||||
|
||||
denali->active_bank = chip;
|
||||
denali->active_bank = cs;
|
||||
}
|
||||
|
||||
static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
static int denali_waitfunc(struct nand_chip *chip)
|
||||
{
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
|
||||
uint32_t irq_status;
|
||||
|
||||
/* R/B# pin transitioned from low to high? */
|
||||
|
@ -930,9 +923,9 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
|
|||
return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
|
||||
}
|
||||
|
||||
static int denali_erase(struct mtd_info *mtd, int page)
|
||||
static int denali_erase(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
|
||||
uint32_t irq_status;
|
||||
|
||||
denali_reset_irq(denali);
|
||||
|
@ -947,10 +940,10 @@ static int denali_erase(struct mtd_info *mtd, int page)
|
|||
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 nand_chip *chip, int chipnr,
|
||||
const struct nand_data_interface *conf)
|
||||
{
|
||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||
struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
|
||||
const struct nand_sdr_timings *timings;
|
||||
unsigned long t_x, mult_x;
|
||||
int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
|
||||
|
@ -1105,12 +1098,17 @@ static void denali_hw_init(struct denali_nand_info *denali)
|
|||
denali->revision = swab16(ioread32(denali->reg + REVISION));
|
||||
|
||||
/*
|
||||
* tell driver how many bit controller will skip before
|
||||
* writing ECC code in OOB, this register may be already
|
||||
* set by firmware. So we read this value out.
|
||||
* if this value is 0, just let it be.
|
||||
* Set how many bytes should be skipped before writing data in OOB.
|
||||
* If a non-zero value has already been set (by firmware or something),
|
||||
* just use it. Otherwise, set the driver default.
|
||||
*/
|
||||
denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES);
|
||||
if (!denali->oob_skip_bytes) {
|
||||
denali->oob_skip_bytes = DENALI_DEFAULT_OOB_SKIP_BYTES;
|
||||
iowrite32(denali->oob_skip_bytes,
|
||||
denali->reg + SPARE_AREA_SKIP_BYTES);
|
||||
}
|
||||
|
||||
denali_detect_max_banks(denali);
|
||||
iowrite32(0x0F, denali->reg + RB_PIN_ENABLED);
|
||||
iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
|
||||
|
@ -1277,11 +1275,11 @@ static int denali_attach_chip(struct nand_chip *chip)
|
|||
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
|
||||
|
||||
if (chip->options & NAND_BUSWIDTH_16) {
|
||||
chip->read_buf = denali_read_buf16;
|
||||
chip->write_buf = denali_write_buf16;
|
||||
chip->legacy.read_buf = denali_read_buf16;
|
||||
chip->legacy.write_buf = denali_write_buf16;
|
||||
} else {
|
||||
chip->read_buf = denali_read_buf;
|
||||
chip->write_buf = denali_write_buf;
|
||||
chip->legacy.read_buf = denali_read_buf;
|
||||
chip->legacy.write_buf = denali_write_buf;
|
||||
}
|
||||
chip->ecc.read_page = denali_read_page;
|
||||
chip->ecc.read_page_raw = denali_read_page_raw;
|
||||
|
@ -1289,7 +1287,7 @@ static int denali_attach_chip(struct nand_chip *chip)
|
|||
chip->ecc.write_page_raw = denali_write_page_raw;
|
||||
chip->ecc.read_oob = denali_read_oob;
|
||||
chip->ecc.write_oob = denali_write_oob;
|
||||
chip->erase = denali_erase;
|
||||
chip->legacy.erase = denali_erase;
|
||||
|
||||
ret = denali_multidev_fixup(denali);
|
||||
if (ret)
|
||||
|
@ -1358,12 +1356,11 @@ int denali_init(struct denali_nand_info *denali)
|
|||
mtd->name = "denali-nand";
|
||||
|
||||
chip->select_chip = denali_select_chip;
|
||||
chip->read_byte = denali_read_byte;
|
||||
chip->write_byte = denali_write_byte;
|
||||
chip->read_word = denali_read_word;
|
||||
chip->cmd_ctrl = denali_cmd_ctrl;
|
||||
chip->dev_ready = denali_dev_ready;
|
||||
chip->waitfunc = denali_waitfunc;
|
||||
chip->legacy.read_byte = denali_read_byte;
|
||||
chip->legacy.write_byte = denali_write_byte;
|
||||
chip->legacy.cmd_ctrl = denali_cmd_ctrl;
|
||||
chip->legacy.dev_ready = denali_dev_ready;
|
||||
chip->legacy.waitfunc = denali_waitfunc;
|
||||
|
||||
if (features & FEATURES__INDEX_ADDR) {
|
||||
denali->host_read = denali_indexed_read;
|
||||
|
@ -1378,7 +1375,7 @@ int denali_init(struct denali_nand_info *denali)
|
|||
chip->setup_data_interface = denali_setup_data_interface;
|
||||
|
||||
chip->dummy_controller.ops = &denali_controller_ops;
|
||||
ret = nand_scan(mtd, denali->max_banks);
|
||||
ret = nand_scan(chip, denali->max_banks);
|
||||
if (ret)
|
||||
goto disable_irq;
|
||||
|
||||
|
@ -1401,9 +1398,11 @@ EXPORT_SYMBOL(denali_init);
|
|||
|
||||
void denali_remove(struct denali_nand_info *denali)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(&denali->nand);
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(&denali->nand);
|
||||
denali_disable_irq(denali);
|
||||
}
|
||||
EXPORT_SYMBOL(denali_remove);
|
||||
|
||||
MODULE_DESCRIPTION("Driver core for Denali NAND controller");
|
||||
MODULE_AUTHOR("Intel Corporation and its suppliers");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -1,15 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* NAND Flash Controller Device Driver
|
||||
* Copyright (c) 2009 - 2010, Intel Corporation and its suppliers.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#ifndef __DENALI_H__
|
||||
|
|
|
@ -1,16 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* NAND Flash Controller Device Driver for DT
|
||||
*
|
||||
* Copyright © 2011, Picochip.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
@ -202,6 +194,6 @@ static struct platform_driver denali_dt_driver = {
|
|||
};
|
||||
module_platform_driver(denali_dt_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Jamie Iles");
|
||||
MODULE_DESCRIPTION("DT driver for Denali NAND controller");
|
||||
|
|
|
@ -1,15 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* NAND Flash Controller Device Driver
|
||||
* Copyright © 2009-2010, Intel Corporation and its suppliers.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
|
|
@ -83,9 +83,9 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
|
|||
#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
|
||||
#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
|
||||
|
||||
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
static void doc200x_hwcontrol(struct nand_chip *this, int cmd,
|
||||
unsigned int bitmask);
|
||||
static void doc200x_select_chip(struct mtd_info *mtd, int chip);
|
||||
static void doc200x_select_chip(struct nand_chip *this, int chip);
|
||||
|
||||
static int debug = 0;
|
||||
module_param(debug, int, 0);
|
||||
|
@ -290,9 +290,8 @@ static inline int DoC_WaitReady(struct doc_priv *doc)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
|
||||
static void doc2000_write_byte(struct nand_chip *this, u_char datum)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
|
||||
|
@ -302,9 +301,8 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
|
|||
WriteDOC(datum, docptr, 2k_CDSN_IO);
|
||||
}
|
||||
|
||||
static u_char doc2000_read_byte(struct mtd_info *mtd)
|
||||
static u_char doc2000_read_byte(struct nand_chip *this)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
u_char ret;
|
||||
|
@ -317,9 +315,9 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
static void doc2000_writebuf(struct nand_chip *this, const u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
int i;
|
||||
|
@ -334,9 +332,8 @@ static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
|
|||
printk("\n");
|
||||
}
|
||||
|
||||
static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void doc2000_readbuf(struct nand_chip *this, u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
int i;
|
||||
|
@ -344,14 +341,12 @@ static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len)
|
|||
if (debug)
|
||||
printk("readbuf of %d bytes: ", len);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
|
||||
}
|
||||
}
|
||||
|
||||
static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void doc2000_readbuf_dword(struct nand_chip *this, u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
int i;
|
||||
|
@ -376,19 +371,19 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
|
|||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
uint16_t ret;
|
||||
|
||||
doc200x_select_chip(mtd, nr);
|
||||
doc200x_hwcontrol(mtd, NAND_CMD_READID,
|
||||
doc200x_select_chip(this, nr);
|
||||
doc200x_hwcontrol(this, NAND_CMD_READID,
|
||||
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
||||
doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
doc200x_hwcontrol(this, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
||||
doc200x_hwcontrol(this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
/* We can't use dev_ready here, but at least we wait for the
|
||||
* command to complete
|
||||
*/
|
||||
udelay(50);
|
||||
|
||||
ret = this->read_byte(mtd) << 8;
|
||||
ret |= this->read_byte(mtd);
|
||||
ret = this->legacy.read_byte(this) << 8;
|
||||
ret |= this->legacy.read_byte(this);
|
||||
|
||||
if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
|
||||
/* First chip probe. See if we get same results by 32-bit access */
|
||||
|
@ -398,10 +393,10 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
|
|||
} ident;
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
|
||||
doc200x_hwcontrol(mtd, NAND_CMD_READID,
|
||||
doc200x_hwcontrol(this, NAND_CMD_READID,
|
||||
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
||||
doc200x_hwcontrol(mtd, NAND_CMD_NONE,
|
||||
doc200x_hwcontrol(this, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
|
||||
doc200x_hwcontrol(this, NAND_CMD_NONE,
|
||||
NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
udelay(50);
|
||||
|
@ -409,7 +404,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
|
|||
ident.dword = readl(docptr + DoC_2k_CDSN_IO);
|
||||
if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
|
||||
pr_info("DiskOnChip 2000 responds to DWORD access\n");
|
||||
this->read_buf = &doc2000_readbuf_dword;
|
||||
this->legacy.read_buf = &doc2000_readbuf_dword;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -438,7 +433,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd)
|
|||
pr_debug("Detected %d chips per floor.\n", i);
|
||||
}
|
||||
|
||||
static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
|
||||
static int doc200x_wait(struct nand_chip *this)
|
||||
{
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
|
||||
|
@ -447,14 +442,13 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
|
|||
DoC_WaitReady(doc);
|
||||
nand_status_op(this, NULL);
|
||||
DoC_WaitReady(doc);
|
||||
status = (int)this->read_byte(mtd);
|
||||
status = (int)this->legacy.read_byte(this);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
|
||||
static void doc2001_write_byte(struct nand_chip *this, u_char datum)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
|
||||
|
@ -463,9 +457,8 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
|
|||
WriteDOC(datum, docptr, WritePipeTerm);
|
||||
}
|
||||
|
||||
static u_char doc2001_read_byte(struct mtd_info *mtd)
|
||||
static u_char doc2001_read_byte(struct nand_chip *this)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
|
||||
|
@ -477,9 +470,8 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
|
|||
return ReadDOC(docptr, LastDataRead);
|
||||
}
|
||||
|
||||
static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
static void doc2001_writebuf(struct nand_chip *this, const u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
int i;
|
||||
|
@ -490,9 +482,8 @@ static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
|
|||
WriteDOC(0x00, docptr, WritePipeTerm);
|
||||
}
|
||||
|
||||
static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void doc2001_readbuf(struct nand_chip *this, u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
int i;
|
||||
|
@ -507,9 +498,8 @@ static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len)
|
|||
buf[i] = ReadDOC(docptr, LastDataRead);
|
||||
}
|
||||
|
||||
static u_char doc2001plus_read_byte(struct mtd_info *mtd)
|
||||
static u_char doc2001plus_read_byte(struct nand_chip *this)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
u_char ret;
|
||||
|
@ -522,9 +512,8 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
static void doc2001plus_writebuf(struct nand_chip *this, const u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
int i;
|
||||
|
@ -540,9 +529,8 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int le
|
|||
printk("\n");
|
||||
}
|
||||
|
||||
static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void doc2001plus_readbuf(struct nand_chip *this, u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
int i;
|
||||
|
@ -571,9 +559,8 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len)
|
|||
printk("\n");
|
||||
}
|
||||
|
||||
static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void doc2001plus_select_chip(struct nand_chip *this, int chip)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
int floor = 0;
|
||||
|
@ -598,9 +585,8 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
|
|||
doc->curfloor = floor;
|
||||
}
|
||||
|
||||
static void doc200x_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void doc200x_select_chip(struct nand_chip *this, int chip)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
int floor = 0;
|
||||
|
@ -615,12 +601,12 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
|
|||
chip -= (floor * doc->chips_per_floor);
|
||||
|
||||
/* 11.4.4 -- deassert CE before changing chip */
|
||||
doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
|
||||
doc200x_hwcontrol(this, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
|
||||
|
||||
WriteDOC(floor, docptr, FloorSelect);
|
||||
WriteDOC(chip, docptr, CDSNDeviceSelect);
|
||||
|
||||
doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
doc200x_hwcontrol(this, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
doc->curchip = chip;
|
||||
doc->curfloor = floor;
|
||||
|
@ -628,10 +614,9 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
|
|||
|
||||
#define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE)
|
||||
|
||||
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
static void doc200x_hwcontrol(struct nand_chip *this, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
|
||||
|
@ -646,15 +631,16 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
|
|||
}
|
||||
if (cmd != NAND_CMD_NONE) {
|
||||
if (DoC_is_2000(doc))
|
||||
doc2000_write_byte(mtd, cmd);
|
||||
doc2000_write_byte(this, cmd);
|
||||
else
|
||||
doc2001_write_byte(mtd, cmd);
|
||||
doc2001_write_byte(this, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
|
||||
static void doc2001plus_command(struct nand_chip *this, unsigned command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(this);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
|
||||
|
@ -729,13 +715,13 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
|
|||
return;
|
||||
|
||||
case NAND_CMD_RESET:
|
||||
if (this->dev_ready)
|
||||
if (this->legacy.dev_ready)
|
||||
break;
|
||||
udelay(this->chip_delay);
|
||||
udelay(this->legacy.chip_delay);
|
||||
WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);
|
||||
WriteDOC(0, docptr, Mplus_WritePipeTerm);
|
||||
WriteDOC(0, docptr, Mplus_WritePipeTerm);
|
||||
while (!(this->read_byte(mtd) & 0x40)) ;
|
||||
while (!(this->legacy.read_byte(this) & 0x40)) ;
|
||||
return;
|
||||
|
||||
/* This applies to read commands */
|
||||
|
@ -744,8 +730,8 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
|
|||
* If we don't have access to the busy pin, we apply the given
|
||||
* command delay
|
||||
*/
|
||||
if (!this->dev_ready) {
|
||||
udelay(this->chip_delay);
|
||||
if (!this->legacy.dev_ready) {
|
||||
udelay(this->legacy.chip_delay);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -754,12 +740,11 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
|
|||
* any case on any machine. */
|
||||
ndelay(100);
|
||||
/* wait until command is processed */
|
||||
while (!this->dev_ready(mtd)) ;
|
||||
while (!this->legacy.dev_ready(this)) ;
|
||||
}
|
||||
|
||||
static int doc200x_dev_ready(struct mtd_info *mtd)
|
||||
static int doc200x_dev_ready(struct nand_chip *this)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
|
||||
|
@ -790,16 +775,15 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
|
|||
}
|
||||
}
|
||||
|
||||
static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
|
||||
static int doc200x_block_bad(struct nand_chip *this, loff_t ofs)
|
||||
{
|
||||
/* This is our last resort if we couldn't find or create a BBT. Just
|
||||
pretend all blocks are good. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
static void doc200x_enable_hwecc(struct nand_chip *this, int mode)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
|
||||
|
@ -816,9 +800,8 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
|
|||
}
|
||||
}
|
||||
|
||||
static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
static void doc2001plus_enable_hwecc(struct nand_chip *this, int mode)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
|
||||
|
@ -836,9 +819,9 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
|
|||
}
|
||||
|
||||
/* This code is only called on write */
|
||||
static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsigned char *ecc_code)
|
||||
static int doc200x_calculate_ecc(struct nand_chip *this, const u_char *dat,
|
||||
unsigned char *ecc_code)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
int i;
|
||||
|
@ -895,11 +878,10 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsign
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
static int doc200x_correct_data(struct nand_chip *this, u_char *dat,
|
||||
u_char *read_ecc, u_char *isnull)
|
||||
{
|
||||
int i, ret = 0;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
uint8_t calc_ecc[6];
|
||||
|
@ -1357,9 +1339,9 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
|
|||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
|
||||
this->read_byte = doc2000_read_byte;
|
||||
this->write_buf = doc2000_writebuf;
|
||||
this->read_buf = doc2000_readbuf;
|
||||
this->legacy.read_byte = doc2000_read_byte;
|
||||
this->legacy.write_buf = doc2000_writebuf;
|
||||
this->legacy.read_buf = doc2000_readbuf;
|
||||
doc->late_init = nftl_scan_bbt;
|
||||
|
||||
doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
|
||||
|
@ -1373,9 +1355,9 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
|
|||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
|
||||
this->read_byte = doc2001_read_byte;
|
||||
this->write_buf = doc2001_writebuf;
|
||||
this->read_buf = doc2001_readbuf;
|
||||
this->legacy.read_byte = doc2001_read_byte;
|
||||
this->legacy.write_buf = doc2001_writebuf;
|
||||
this->legacy.read_buf = doc2001_readbuf;
|
||||
|
||||
ReadDOC(doc->virtadr, ChipID);
|
||||
ReadDOC(doc->virtadr, ChipID);
|
||||
|
@ -1403,13 +1385,13 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
|
|||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct doc_priv *doc = nand_get_controller_data(this);
|
||||
|
||||
this->read_byte = doc2001plus_read_byte;
|
||||
this->write_buf = doc2001plus_writebuf;
|
||||
this->read_buf = doc2001plus_readbuf;
|
||||
this->legacy.read_byte = doc2001plus_read_byte;
|
||||
this->legacy.write_buf = doc2001plus_writebuf;
|
||||
this->legacy.read_buf = doc2001plus_readbuf;
|
||||
doc->late_init = inftl_scan_bbt;
|
||||
this->cmd_ctrl = NULL;
|
||||
this->legacy.cmd_ctrl = NULL;
|
||||
this->select_chip = doc2001plus_select_chip;
|
||||
this->cmdfunc = doc2001plus_command;
|
||||
this->legacy.cmdfunc = doc2001plus_command;
|
||||
this->ecc.hwctl = doc2001plus_enable_hwecc;
|
||||
|
||||
doc->chips_per_floor = 1;
|
||||
|
@ -1587,10 +1569,10 @@ static int __init doc_probe(unsigned long physadr)
|
|||
|
||||
nand_set_controller_data(nand, doc);
|
||||
nand->select_chip = doc200x_select_chip;
|
||||
nand->cmd_ctrl = doc200x_hwcontrol;
|
||||
nand->dev_ready = doc200x_dev_ready;
|
||||
nand->waitfunc = doc200x_wait;
|
||||
nand->block_bad = doc200x_block_bad;
|
||||
nand->legacy.cmd_ctrl = doc200x_hwcontrol;
|
||||
nand->legacy.dev_ready = doc200x_dev_ready;
|
||||
nand->legacy.waitfunc = doc200x_wait;
|
||||
nand->legacy.block_bad = doc200x_block_bad;
|
||||
nand->ecc.hwctl = doc200x_enable_hwecc;
|
||||
nand->ecc.calculate = doc200x_calculate_ecc;
|
||||
nand->ecc.correct = doc200x_correct_data;
|
||||
|
@ -1620,14 +1602,14 @@ static int __init doc_probe(unsigned long physadr)
|
|||
else
|
||||
numchips = doc2001_init(mtd);
|
||||
|
||||
if ((ret = nand_scan(mtd, numchips)) || (ret = doc->late_init(mtd))) {
|
||||
if ((ret = nand_scan(nand, numchips)) || (ret = doc->late_init(mtd))) {
|
||||
/* DBB note: i believe nand_release is necessary here, as
|
||||
buffers may have been allocated in nand_base. Check with
|
||||
Thomas. FIX ME! */
|
||||
/* nand_release will call mtd_device_unregister, but we
|
||||
haven't yet added it. This is handled without incident by
|
||||
mtd_device_unregister, as far as I can tell. */
|
||||
nand_release(mtd);
|
||||
nand_release(nand);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -1662,7 +1644,7 @@ static void release_nanddoc(void)
|
|||
doc = nand_get_controller_data(nand);
|
||||
|
||||
nextmtd = doc->nextdoc;
|
||||
nand_release(mtd);
|
||||
nand_release(nand);
|
||||
iounmap(doc->virtadr);
|
||||
release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
|
||||
free_rs(doc->rs_decoder);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -317,10 +317,10 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
|
|||
}
|
||||
|
||||
/* cmdfunc send commands to the FCM */
|
||||
static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
||||
static void fsl_elbc_cmdfunc(struct nand_chip *chip, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
|
||||
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
|
||||
|
@ -533,7 +533,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
|||
}
|
||||
}
|
||||
|
||||
static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void fsl_elbc_select_chip(struct nand_chip *chip, int cs)
|
||||
{
|
||||
/* The hardware does not seem to support multiple
|
||||
* chips per bank.
|
||||
|
@ -543,9 +543,9 @@ static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip)
|
|||
/*
|
||||
* Write buf to the FCM Controller Data Buffer
|
||||
*/
|
||||
static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
||||
static void fsl_elbc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
|
||||
unsigned int bufsize = mtd->writesize + mtd->oobsize;
|
||||
|
@ -581,9 +581,8 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
|||
* read a byte from either the FCM hardware buffer if it has any data left
|
||||
* otherwise issue a command to read a single byte.
|
||||
*/
|
||||
static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
|
||||
static u8 fsl_elbc_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
|
||||
|
||||
|
@ -598,9 +597,8 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
|
|||
/*
|
||||
* Read from the FCM Controller Data Buffer
|
||||
*/
|
||||
static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
||||
static void fsl_elbc_read_buf(struct nand_chip *chip, u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
|
||||
int avail;
|
||||
|
@ -623,7 +621,7 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
|||
/* This function is called after Program and Erase Operations to
|
||||
* check for success or failure.
|
||||
*/
|
||||
static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
static int fsl_elbc_wait(struct nand_chip *chip)
|
||||
{
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
|
||||
|
@ -660,8 +658,8 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
|
|||
chip->chipsize);
|
||||
dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
|
||||
chip->pagemask);
|
||||
dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
|
||||
chip->chip_delay);
|
||||
dev_dbg(priv->dev, "fsl_elbc_init: nand->legacy.chip_delay = %d\n",
|
||||
chip->legacy.chip_delay);
|
||||
dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
|
||||
chip->badblockpos);
|
||||
dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
|
||||
|
@ -710,18 +708,19 @@ static const struct nand_controller_ops fsl_elbc_controller_ops = {
|
|||
.attach_chip = fsl_elbc_attach_chip,
|
||||
};
|
||||
|
||||
static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int fsl_elbc_read_page(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
|
||||
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
|
||||
|
||||
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
|
||||
if (oob_required)
|
||||
fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
fsl_elbc_read_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
|
||||
if (fsl_elbc_wait(chip) & NAND_STATUS_FAIL)
|
||||
mtd->ecc_stats.failed++;
|
||||
|
||||
return elbc_fcm_ctrl->max_bitflips;
|
||||
|
@ -730,11 +729,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
/* ECC will be calculated automatically, and errors will be detected in
|
||||
* waitfunc.
|
||||
*/
|
||||
static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
static int fsl_elbc_write_page(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
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(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
@ -742,13 +743,15 @@ static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
/* ECC will be calculated automatically, and errors will be detected in
|
||||
* waitfunc.
|
||||
*/
|
||||
static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint32_t offset, uint32_t data_len,
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
static int fsl_elbc_write_subpage(struct nand_chip *chip, uint32_t offset,
|
||||
uint32_t data_len, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
|
||||
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
|
||||
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
fsl_elbc_write_buf(chip, buf, mtd->writesize);
|
||||
fsl_elbc_write_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
|
@ -773,14 +776,14 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
|
|||
|
||||
/* fill in nand_chip structure */
|
||||
/* set up function call table */
|
||||
chip->read_byte = fsl_elbc_read_byte;
|
||||
chip->write_buf = fsl_elbc_write_buf;
|
||||
chip->read_buf = fsl_elbc_read_buf;
|
||||
chip->legacy.read_byte = fsl_elbc_read_byte;
|
||||
chip->legacy.write_buf = fsl_elbc_write_buf;
|
||||
chip->legacy.read_buf = fsl_elbc_read_buf;
|
||||
chip->select_chip = fsl_elbc_select_chip;
|
||||
chip->cmdfunc = fsl_elbc_cmdfunc;
|
||||
chip->waitfunc = fsl_elbc_wait;
|
||||
chip->set_features = nand_get_set_features_notsupp;
|
||||
chip->get_features = nand_get_set_features_notsupp;
|
||||
chip->legacy.cmdfunc = fsl_elbc_cmdfunc;
|
||||
chip->legacy.waitfunc = fsl_elbc_wait;
|
||||
chip->legacy.set_features = nand_get_set_features_notsupp;
|
||||
chip->legacy.get_features = nand_get_set_features_notsupp;
|
||||
|
||||
chip->bbt_td = &bbt_main_descr;
|
||||
chip->bbt_md = &bbt_mirror_descr;
|
||||
|
@ -915,7 +918,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
|
|||
goto err;
|
||||
|
||||
priv->chip.controller->ops = &fsl_elbc_controller_ops;
|
||||
ret = nand_scan(mtd, 1);
|
||||
ret = nand_scan(&priv->chip, 1);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
@ -942,9 +945,8 @@ static int fsl_elbc_nand_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
|
||||
struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
|
||||
struct mtd_info *mtd = nand_to_mtd(&priv->chip);
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(&priv->chip);
|
||||
fsl_elbc_chip_remove(priv);
|
||||
|
||||
mutex_lock(&fsl_elbc_nand_mutex);
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/nand_ecc.h>
|
||||
#include <linux/fsl_ifc.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#define ERR_BYTE 0xFF /* Value returned for read
|
||||
bytes when read failed */
|
||||
|
@ -300,9 +301,9 @@ static void fsl_ifc_do_read(struct nand_chip *chip,
|
|||
}
|
||||
|
||||
/* cmdfunc send commands to the IFC NAND Machine */
|
||||
static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
||||
static void fsl_ifc_cmdfunc(struct nand_chip *chip, unsigned int command,
|
||||
int column, int page_addr) {
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
|
||||
|
@ -508,7 +509,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
|||
}
|
||||
}
|
||||
|
||||
static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void fsl_ifc_select_chip(struct nand_chip *chip, int cs)
|
||||
{
|
||||
/* The hardware does not seem to support multiple
|
||||
* chips per bank.
|
||||
|
@ -518,9 +519,9 @@ static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
|
|||
/*
|
||||
* Write buf to the IFC NAND Controller Data Buffer
|
||||
*/
|
||||
static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
||||
static void fsl_ifc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
unsigned int bufsize = mtd->writesize + mtd->oobsize;
|
||||
|
||||
|
@ -544,9 +545,8 @@ static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
|||
* Read a byte from either the IFC hardware buffer
|
||||
* read function for 8-bit buswidth
|
||||
*/
|
||||
static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t fsl_ifc_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
unsigned int offset;
|
||||
|
||||
|
@ -567,9 +567,8 @@ static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
|
|||
* Read two bytes from the IFC hardware buffer
|
||||
* read function for 16-bit buswith
|
||||
*/
|
||||
static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
|
||||
static uint8_t fsl_ifc_read_byte16(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
uint16_t data;
|
||||
|
||||
|
@ -590,9 +589,8 @@ static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
|
|||
/*
|
||||
* Read from the IFC Controller Data Buffer
|
||||
*/
|
||||
static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
||||
static void fsl_ifc_read_buf(struct nand_chip *chip, u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
int avail;
|
||||
|
||||
|
@ -616,8 +614,9 @@ static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
|||
* This function is called after Program and Erase Operations to
|
||||
* check for success or failure.
|
||||
*/
|
||||
static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
static int fsl_ifc_wait(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
|
||||
|
@ -678,20 +677,21 @@ static int check_erased_page(struct nand_chip *chip, u8 *buf)
|
|||
return bitflips;
|
||||
}
|
||||
|
||||
static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int fsl_ifc_read_page(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct fsl_ifc_mtd *priv = nand_get_controller_data(chip);
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
|
||||
|
||||
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
|
||||
if (oob_required)
|
||||
fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
fsl_ifc_read_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) {
|
||||
if (!oob_required)
|
||||
fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
fsl_ifc_read_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return check_erased_page(chip, buf);
|
||||
}
|
||||
|
@ -705,11 +705,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
/* ECC will be calculated automatically, and errors will be detected in
|
||||
* waitfunc.
|
||||
*/
|
||||
static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
static int fsl_ifc_write_page(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
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(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
@ -725,8 +727,8 @@ static int fsl_ifc_attach_chip(struct nand_chip *chip)
|
|||
chip->chipsize);
|
||||
dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
|
||||
chip->pagemask);
|
||||
dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__,
|
||||
chip->chip_delay);
|
||||
dev_dbg(priv->dev, "%s: nand->legacy.chip_delay = %d\n", __func__,
|
||||
chip->legacy.chip_delay);
|
||||
dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__,
|
||||
chip->badblockpos);
|
||||
dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__,
|
||||
|
@ -761,7 +763,7 @@ static const struct nand_controller_ops fsl_ifc_controller_ops = {
|
|||
.attach_chip = fsl_ifc_attach_chip,
|
||||
};
|
||||
|
||||
static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
|
||||
static int fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
|
||||
{
|
||||
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
|
||||
struct fsl_ifc_runtime __iomem *ifc_runtime = ctrl->rregs;
|
||||
|
@ -769,6 +771,27 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
|
|||
uint32_t csor = 0, csor_8k = 0, csor_ext = 0;
|
||||
uint32_t cs = priv->bank;
|
||||
|
||||
if (ctrl->version < FSL_IFC_VERSION_1_1_0)
|
||||
return 0;
|
||||
|
||||
if (ctrl->version > FSL_IFC_VERSION_1_1_0) {
|
||||
u32 ncfgr, status;
|
||||
int ret;
|
||||
|
||||
/* Trigger auto initialization */
|
||||
ncfgr = ifc_in32(&ifc_runtime->ifc_nand.ncfgr);
|
||||
ifc_out32(ncfgr | IFC_NAND_NCFGR_SRAM_INIT_EN, &ifc_runtime->ifc_nand.ncfgr);
|
||||
|
||||
/* Wait until done */
|
||||
ret = readx_poll_timeout(ifc_in32, &ifc_runtime->ifc_nand.ncfgr,
|
||||
status, !(status & IFC_NAND_NCFGR_SRAM_INIT_EN),
|
||||
10, IFC_TIMEOUT_MSECS * 1000);
|
||||
if (ret)
|
||||
dev_err(priv->dev, "Failed to initialize SRAM!\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Save CSOR and CSOR_ext */
|
||||
csor = ifc_in32(&ifc_global->csor_cs[cs].csor);
|
||||
csor_ext = ifc_in32(&ifc_global->csor_cs[cs].csor_ext);
|
||||
|
@ -805,12 +828,16 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
|
|||
wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
|
||||
msecs_to_jiffies(IFC_TIMEOUT_MSECS));
|
||||
|
||||
if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
|
||||
if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) {
|
||||
pr_err("fsl-ifc: Failed to Initialise SRAM\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Restore CSOR and CSOR_ext */
|
||||
ifc_out32(csor, &ifc_global->csor_cs[cs].csor);
|
||||
ifc_out32(csor_ext, &ifc_global->csor_cs[cs].csor_ext);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
|
||||
|
@ -821,6 +848,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
|
|||
struct nand_chip *chip = &priv->chip;
|
||||
struct mtd_info *mtd = nand_to_mtd(&priv->chip);
|
||||
u32 csor;
|
||||
int ret;
|
||||
|
||||
/* Fill in fsl_ifc_mtd structure */
|
||||
mtd->dev.parent = priv->dev;
|
||||
|
@ -830,17 +858,17 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
|
|||
/* set up function call table */
|
||||
if ((ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr))
|
||||
& CSPR_PORT_SIZE_16)
|
||||
chip->read_byte = fsl_ifc_read_byte16;
|
||||
chip->legacy.read_byte = fsl_ifc_read_byte16;
|
||||
else
|
||||
chip->read_byte = fsl_ifc_read_byte;
|
||||
chip->legacy.read_byte = fsl_ifc_read_byte;
|
||||
|
||||
chip->write_buf = fsl_ifc_write_buf;
|
||||
chip->read_buf = fsl_ifc_read_buf;
|
||||
chip->legacy.write_buf = fsl_ifc_write_buf;
|
||||
chip->legacy.read_buf = fsl_ifc_read_buf;
|
||||
chip->select_chip = fsl_ifc_select_chip;
|
||||
chip->cmdfunc = fsl_ifc_cmdfunc;
|
||||
chip->waitfunc = fsl_ifc_wait;
|
||||
chip->set_features = nand_get_set_features_notsupp;
|
||||
chip->get_features = nand_get_set_features_notsupp;
|
||||
chip->legacy.cmdfunc = fsl_ifc_cmdfunc;
|
||||
chip->legacy.waitfunc = fsl_ifc_wait;
|
||||
chip->legacy.set_features = nand_get_set_features_notsupp;
|
||||
chip->legacy.get_features = nand_get_set_features_notsupp;
|
||||
|
||||
chip->bbt_td = &bbt_main_descr;
|
||||
chip->bbt_md = &bbt_mirror_descr;
|
||||
|
@ -853,10 +881,10 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
|
|||
|
||||
if (ifc_in32(&ifc_global->cspr_cs[priv->bank].cspr)
|
||||
& CSPR_PORT_SIZE_16) {
|
||||
chip->read_byte = fsl_ifc_read_byte16;
|
||||
chip->legacy.read_byte = fsl_ifc_read_byte16;
|
||||
chip->options |= NAND_BUSWIDTH_16;
|
||||
} else {
|
||||
chip->read_byte = fsl_ifc_read_byte;
|
||||
chip->legacy.read_byte = fsl_ifc_read_byte;
|
||||
}
|
||||
|
||||
chip->controller = &ifc_nand_ctrl->controller;
|
||||
|
@ -914,8 +942,9 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
|
|||
chip->ecc.algo = NAND_ECC_HAMMING;
|
||||
}
|
||||
|
||||
if (ctrl->version >= FSL_IFC_VERSION_1_1_0)
|
||||
fsl_ifc_sram_init(priv);
|
||||
ret = fsl_ifc_sram_init(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* As IFC version 2.0.0 has 16KB of internal SRAM as compared to older
|
||||
|
@ -1051,7 +1080,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
|
|||
goto err;
|
||||
|
||||
priv->chip.controller->ops = &fsl_ifc_controller_ops;
|
||||
ret = nand_scan(mtd, 1);
|
||||
ret = nand_scan(&priv->chip, 1);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
@ -1077,9 +1106,8 @@ err:
|
|||
static int fsl_ifc_nand_remove(struct platform_device *dev)
|
||||
{
|
||||
struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
|
||||
struct mtd_info *mtd = nand_to_mtd(&priv->chip);
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(&priv->chip);
|
||||
fsl_ifc_chip_remove(priv);
|
||||
|
||||
mutex_lock(&fsl_ifc_nand_mutex);
|
||||
|
|
|
@ -52,9 +52,9 @@ static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo)
|
|||
chip);
|
||||
}
|
||||
|
||||
static int fun_chip_ready(struct mtd_info *mtd)
|
||||
static int fun_chip_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
|
||||
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
|
||||
|
||||
if (gpio_get_value(fun->rnb_gpio[fun->mchip_number]))
|
||||
return 1;
|
||||
|
@ -69,7 +69,7 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun)
|
|||
struct mtd_info *mtd = nand_to_mtd(&fun->chip);
|
||||
int cnt = 1000000;
|
||||
|
||||
while (--cnt && !fun_chip_ready(mtd))
|
||||
while (--cnt && !fun_chip_ready(&fun->chip))
|
||||
cpu_relax();
|
||||
if (!cnt)
|
||||
dev_err(fun->dev, "tired waiting for RNB\n");
|
||||
|
@ -78,10 +78,9 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun)
|
|||
}
|
||||
}
|
||||
|
||||
static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
static void fun_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
|
||||
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
|
||||
u32 mar;
|
||||
|
||||
if (!(ctrl & fun->last_ctrl)) {
|
||||
|
@ -102,51 +101,50 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
|||
|
||||
mar = (cmd << (32 - fun->upm.width)) |
|
||||
fun->mchip_offsets[fun->mchip_number];
|
||||
fsl_upm_run_pattern(&fun->upm, chip->IO_ADDR_R, mar);
|
||||
fsl_upm_run_pattern(&fun->upm, chip->legacy.IO_ADDR_R, mar);
|
||||
|
||||
if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN)
|
||||
fun_wait_rnb(fun);
|
||||
}
|
||||
|
||||
static void fun_select_chip(struct mtd_info *mtd, int mchip_nr)
|
||||
static void fun_select_chip(struct nand_chip *chip, int mchip_nr)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
|
||||
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
|
||||
|
||||
if (mchip_nr == -1) {
|
||||
chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
|
||||
chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
|
||||
} else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) {
|
||||
fun->mchip_number = mchip_nr;
|
||||
chip->IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
|
||||
chip->IO_ADDR_W = chip->IO_ADDR_R;
|
||||
chip->legacy.IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
|
||||
chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
|
||||
} else {
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t fun_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t fun_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
|
||||
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
|
||||
|
||||
return in_8(fun->chip.IO_ADDR_R);
|
||||
return in_8(fun->chip.legacy.IO_ADDR_R);
|
||||
}
|
||||
|
||||
static void fun_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void fun_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
|
||||
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = in_8(fun->chip.IO_ADDR_R);
|
||||
buf[i] = in_8(fun->chip.legacy.IO_ADDR_R);
|
||||
}
|
||||
|
||||
static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
static void fun_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
|
||||
{
|
||||
struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
|
||||
struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip));
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
out_8(fun->chip.IO_ADDR_W, buf[i]);
|
||||
out_8(fun->chip.legacy.IO_ADDR_W, buf[i]);
|
||||
if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE)
|
||||
fun_wait_rnb(fun);
|
||||
}
|
||||
|
@ -162,20 +160,20 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
|
|||
int ret;
|
||||
struct device_node *flash_np;
|
||||
|
||||
fun->chip.IO_ADDR_R = fun->io_base;
|
||||
fun->chip.IO_ADDR_W = fun->io_base;
|
||||
fun->chip.cmd_ctrl = fun_cmd_ctrl;
|
||||
fun->chip.chip_delay = fun->chip_delay;
|
||||
fun->chip.read_byte = fun_read_byte;
|
||||
fun->chip.read_buf = fun_read_buf;
|
||||
fun->chip.write_buf = fun_write_buf;
|
||||
fun->chip.legacy.IO_ADDR_R = fun->io_base;
|
||||
fun->chip.legacy.IO_ADDR_W = fun->io_base;
|
||||
fun->chip.legacy.cmd_ctrl = fun_cmd_ctrl;
|
||||
fun->chip.legacy.chip_delay = fun->chip_delay;
|
||||
fun->chip.legacy.read_byte = fun_read_byte;
|
||||
fun->chip.legacy.read_buf = fun_read_buf;
|
||||
fun->chip.legacy.write_buf = fun_write_buf;
|
||||
fun->chip.ecc.mode = NAND_ECC_SOFT;
|
||||
fun->chip.ecc.algo = NAND_ECC_HAMMING;
|
||||
if (fun->mchip_count > 1)
|
||||
fun->chip.select_chip = fun_select_chip;
|
||||
|
||||
if (fun->rnb_gpio[0] >= 0)
|
||||
fun->chip.dev_ready = fun_chip_ready;
|
||||
fun->chip.legacy.dev_ready = fun_chip_ready;
|
||||
|
||||
mtd->dev.parent = fun->dev;
|
||||
|
||||
|
@ -184,14 +182,14 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
|
|||
return -ENODEV;
|
||||
|
||||
nand_set_flash_node(&fun->chip, flash_np);
|
||||
mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start,
|
||||
flash_np->name);
|
||||
mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%pOFn", (u64)io_res->start,
|
||||
flash_np);
|
||||
if (!mtd->name) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = nand_scan(mtd, fun->mchip_count);
|
||||
ret = nand_scan(&fun->chip, fun->mchip_count);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
@ -326,7 +324,7 @@ static int fun_remove(struct platform_device *ofdev)
|
|||
struct mtd_info *mtd = nand_to_mtd(&fun->chip);
|
||||
int i;
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(&fun->chip);
|
||||
kfree(mtd->name);
|
||||
|
||||
for (i = 0; i < fun->mchip_count; i++) {
|
||||
|
|
|
@ -340,10 +340,9 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
|
||||
static int fsmc_setup_data_interface(struct nand_chip *nand, int csline,
|
||||
const struct nand_data_interface *conf)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct fsmc_nand_data *host = nand_get_controller_data(nand);
|
||||
struct fsmc_nand_timings tims;
|
||||
const struct nand_sdr_timings *sdrt;
|
||||
|
@ -368,9 +367,9 @@ static int fsmc_setup_data_interface(struct mtd_info *mtd, int csline,
|
|||
/*
|
||||
* fsmc_enable_hwecc - Enables Hardware ECC through FSMC registers
|
||||
*/
|
||||
static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
static void fsmc_enable_hwecc(struct nand_chip *chip, int mode)
|
||||
{
|
||||
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
|
||||
struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
|
||||
|
||||
writel_relaxed(readl(host->regs_va + FSMC_PC) & ~FSMC_ECCPLEN_256,
|
||||
host->regs_va + FSMC_PC);
|
||||
|
@ -385,10 +384,10 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
|
|||
* FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction up to
|
||||
* max of 8-bits)
|
||||
*/
|
||||
static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
|
||||
static int fsmc_read_hwecc_ecc4(struct nand_chip *chip, const uint8_t *data,
|
||||
uint8_t *ecc)
|
||||
{
|
||||
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
|
||||
struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
|
||||
uint32_t ecc_tmp;
|
||||
unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
|
||||
|
||||
|
@ -433,10 +432,10 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
|
|||
* FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction up to
|
||||
* max of 1-bit)
|
||||
*/
|
||||
static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
|
||||
static int fsmc_read_hwecc_ecc1(struct nand_chip *chip, const uint8_t *data,
|
||||
uint8_t *ecc)
|
||||
{
|
||||
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
|
||||
struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
|
||||
uint32_t ecc_tmp;
|
||||
|
||||
ecc_tmp = readl_relaxed(host->regs_va + ECC1);
|
||||
|
@ -610,9 +609,9 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
|
|||
}
|
||||
|
||||
/* fsmc_select_chip - assert or deassert nCE */
|
||||
static void fsmc_select_chip(struct mtd_info *mtd, int chipnr)
|
||||
static void fsmc_select_chip(struct nand_chip *chip, int chipnr)
|
||||
{
|
||||
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
|
||||
struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
|
||||
u32 pc;
|
||||
|
||||
/* Support only one CS */
|
||||
|
@ -707,7 +706,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
|
|||
|
||||
/*
|
||||
* fsmc_read_page_hwecc
|
||||
* @mtd: mtd info structure
|
||||
* @chip: nand chip info structure
|
||||
* @buf: buffer to store read data
|
||||
* @oob_required: caller expects OOB data read to chip->oob_poi
|
||||
|
@ -719,9 +717,10 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
|
|||
* After this read, fsmc hardware generates and reports error data bits(up to a
|
||||
* max of 8 bits)
|
||||
*/
|
||||
static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int fsmc_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
int i, j, s, stat, eccsize = chip->ecc.size;
|
||||
int eccbytes = chip->ecc.bytes;
|
||||
int eccsteps = chip->ecc.steps;
|
||||
|
@ -740,7 +739,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
|
||||
for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
|
||||
nand_read_page_op(chip, page, s * eccsize, NULL, 0);
|
||||
chip->ecc.hwctl(mtd, NAND_ECC_READ);
|
||||
chip->ecc.hwctl(chip, NAND_ECC_READ);
|
||||
nand_read_data_op(chip, p, eccsize, false);
|
||||
|
||||
for (j = 0; j < eccbytes;) {
|
||||
|
@ -767,9 +766,9 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
}
|
||||
|
||||
memcpy(&ecc_code[i], oob, chip->ecc.bytes);
|
||||
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
||||
chip->ecc.calculate(chip, p, &ecc_calc[i]);
|
||||
|
||||
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
||||
stat = chip->ecc.correct(chip, p, &ecc_code[i], &ecc_calc[i]);
|
||||
if (stat < 0) {
|
||||
mtd->ecc_stats.failed++;
|
||||
} else {
|
||||
|
@ -791,11 +790,10 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
* calc_ecc is a 104 bit information containing maximum of 8 error
|
||||
* offset informations of 13 bits each in 512 bytes of read data.
|
||||
*/
|
||||
static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
|
||||
static int fsmc_bch8_correct_data(struct nand_chip *chip, uint8_t *dat,
|
||||
uint8_t *read_ecc, uint8_t *calc_ecc)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct fsmc_nand_data *host = mtd_to_fsmc(mtd);
|
||||
struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip));
|
||||
uint32_t err_idx[8];
|
||||
uint32_t num_err, i;
|
||||
uint32_t ecc1, ecc2, ecc3, ecc4;
|
||||
|
@ -951,6 +949,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand)
|
|||
nand->ecc.correct = nand_correct_data;
|
||||
nand->ecc.bytes = 3;
|
||||
nand->ecc.strength = 1;
|
||||
nand->ecc.options |= NAND_ECC_SOFT_HAMMING_SM_ORDER;
|
||||
break;
|
||||
|
||||
case NAND_ECC_SOFT:
|
||||
|
@ -1082,7 +1081,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
|
|||
mtd->dev.parent = &pdev->dev;
|
||||
nand->exec_op = fsmc_exec_op;
|
||||
nand->select_chip = fsmc_select_chip;
|
||||
nand->chip_delay = 30;
|
||||
|
||||
/*
|
||||
* Setup default ECC mode. nand_dt_init() called from nand_scan_ident()
|
||||
|
@ -1125,7 +1123,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
|
|||
* Scan to find existence of the device
|
||||
*/
|
||||
nand->dummy_controller.ops = &fsmc_nand_controller_ops;
|
||||
ret = nand_scan(mtd, 1);
|
||||
ret = nand_scan(nand, 1);
|
||||
if (ret)
|
||||
goto release_dma_write_chan;
|
||||
|
||||
|
@ -1161,7 +1159,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
|
|||
struct fsmc_nand_data *host = platform_get_drvdata(pdev);
|
||||
|
||||
if (host) {
|
||||
nand_release(nand_to_mtd(&host->nand));
|
||||
nand_release(&host->nand);
|
||||
|
||||
if (host->mode == USE_DMA_ACCESS) {
|
||||
dma_release_channel(host->write_dma_chan);
|
||||
|
|
|
@ -73,9 +73,10 @@ static void gpio_nand_dosync(struct gpiomtd *gpiomtd)
|
|||
static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {}
|
||||
#endif
|
||||
|
||||
static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
static void gpio_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
|
||||
struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip));
|
||||
|
||||
gpio_nand_dosync(gpiomtd);
|
||||
|
||||
|
@ -89,13 +90,13 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
|||
if (cmd == NAND_CMD_NONE)
|
||||
return;
|
||||
|
||||
writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W);
|
||||
writeb(cmd, gpiomtd->nand_chip.legacy.IO_ADDR_W);
|
||||
gpio_nand_dosync(gpiomtd);
|
||||
}
|
||||
|
||||
static int gpio_nand_devready(struct mtd_info *mtd)
|
||||
static int gpio_nand_devready(struct nand_chip *chip)
|
||||
{
|
||||
struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
|
||||
struct gpiomtd *gpiomtd = gpio_nand_getpriv(nand_to_mtd(chip));
|
||||
|
||||
return gpiod_get_value(gpiomtd->rdy);
|
||||
}
|
||||
|
@ -194,7 +195,7 @@ static int gpio_nand_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
|
||||
|
||||
nand_release(nand_to_mtd(&gpiomtd->nand_chip));
|
||||
nand_release(&gpiomtd->nand_chip);
|
||||
|
||||
/* Enable write protection and disable the chip */
|
||||
if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
|
||||
|
@ -224,9 +225,9 @@ static int gpio_nand_probe(struct platform_device *pdev)
|
|||
chip = &gpiomtd->nand_chip;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
chip->IO_ADDR_R = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(chip->IO_ADDR_R))
|
||||
return PTR_ERR(chip->IO_ADDR_R);
|
||||
chip->legacy.IO_ADDR_R = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(chip->legacy.IO_ADDR_R))
|
||||
return PTR_ERR(chip->legacy.IO_ADDR_R);
|
||||
|
||||
res = gpio_nand_get_io_sync(pdev);
|
||||
if (res) {
|
||||
|
@ -270,15 +271,15 @@ static int gpio_nand_probe(struct platform_device *pdev)
|
|||
}
|
||||
/* Using RDY pin */
|
||||
if (gpiomtd->rdy)
|
||||
chip->dev_ready = gpio_nand_devready;
|
||||
chip->legacy.dev_ready = gpio_nand_devready;
|
||||
|
||||
nand_set_flash_node(chip, pdev->dev.of_node);
|
||||
chip->IO_ADDR_W = chip->IO_ADDR_R;
|
||||
chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
|
||||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
chip->ecc.algo = NAND_ECC_HAMMING;
|
||||
chip->options = gpiomtd->plat.options;
|
||||
chip->chip_delay = gpiomtd->plat.chip_delay;
|
||||
chip->cmd_ctrl = gpio_nand_cmd_ctrl;
|
||||
chip->legacy.chip_delay = gpiomtd->plat.chip_delay;
|
||||
chip->legacy.cmd_ctrl = gpio_nand_cmd_ctrl;
|
||||
|
||||
mtd = nand_to_mtd(chip);
|
||||
mtd->dev.parent = dev;
|
||||
|
@ -289,7 +290,7 @@ static int gpio_nand_probe(struct platform_device *pdev)
|
|||
if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp))
|
||||
gpiod_direction_output(gpiomtd->nwp, 1);
|
||||
|
||||
ret = nand_scan(mtd, 1);
|
||||
ret = nand_scan(chip, 1);
|
||||
if (ret)
|
||||
goto err_wp;
|
||||
|
||||
|
|
|
@ -471,10 +471,9 @@ void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
|
|||
udelay(dll_wait_time_us);
|
||||
}
|
||||
|
||||
int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr,
|
||||
int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
|
||||
const struct nand_data_interface *conf)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
const struct nand_sdr_timings *sdr;
|
||||
|
||||
|
|
|
@ -783,9 +783,8 @@ error_alloc:
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
|
||||
static void gpmi_cmd_ctrl(struct nand_chip *chip, int data, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
int ret;
|
||||
|
||||
|
@ -817,17 +816,15 @@ static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
|
|||
this->command_length = 0;
|
||||
}
|
||||
|
||||
static int gpmi_dev_ready(struct mtd_info *mtd)
|
||||
static int gpmi_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
|
||||
return gpmi_is_ready(this, this->current_chip);
|
||||
}
|
||||
|
||||
static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
|
||||
static void gpmi_select_chip(struct nand_chip *chip, int chipnr)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
int ret;
|
||||
|
||||
|
@ -859,9 +856,8 @@ static void gpmi_select_chip(struct mtd_info *mtd, int chipnr)
|
|||
this->current_chip = chipnr;
|
||||
}
|
||||
|
||||
static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void gpmi_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
|
||||
dev_dbg(this->dev, "len is %d\n", len);
|
||||
|
@ -869,9 +865,8 @@ static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
|||
gpmi_read_data(this, buf, len);
|
||||
}
|
||||
|
||||
static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
static void gpmi_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
|
||||
dev_dbg(this->dev, "len is %d\n", len);
|
||||
|
@ -879,13 +874,12 @@ static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
|||
gpmi_send_data(this, buf, len);
|
||||
}
|
||||
|
||||
static uint8_t gpmi_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t gpmi_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
uint8_t *buf = this->data_buffer_dma;
|
||||
|
||||
gpmi_read_buf(mtd, buf, 1);
|
||||
gpmi_read_buf(chip, buf, 1);
|
||||
return buf[0];
|
||||
}
|
||||
|
||||
|
@ -1085,8 +1079,8 @@ static int gpmi_ecc_read_page_data(struct nand_chip *chip,
|
|||
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)
|
||||
static int gpmi_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
nand_read_page_op(chip, page, 0, NULL, 0);
|
||||
|
||||
|
@ -1094,8 +1088,8 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
}
|
||||
|
||||
/* Fake a virtual small page for the subpage read */
|
||||
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)
|
||||
static int gpmi_ecc_read_subpage(struct nand_chip *chip, uint32_t offs,
|
||||
uint32_t len, uint8_t *buf, int page)
|
||||
{
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
void __iomem *bch_regs = this->resources.bch_regs;
|
||||
|
@ -1130,7 +1124,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
dev_dbg(this->dev,
|
||||
"page:%d, first:%d, last:%d, marker at:%d\n",
|
||||
page, first, last, marker_pos);
|
||||
return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
|
||||
return gpmi_ecc_read_page(chip, buf, 0, page);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1182,9 +1176,10 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return max_bitflips;
|
||||
}
|
||||
|
||||
static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
static int gpmi_ecc_write_page(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
struct bch_geometry *nfc_geo = &this->bch_geometry;
|
||||
const void *payload_virt;
|
||||
|
@ -1324,9 +1319,9 @@ exit_auxiliary:
|
|||
* ECC-based or raw view of the page is implicit in which function it calls
|
||||
* (there is a similar pair of ECC-based/raw functions for writing).
|
||||
*/
|
||||
static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int gpmi_ecc_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
|
||||
dev_dbg(this->dev, "page number is %d\n", page);
|
||||
|
@ -1335,7 +1330,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
|
||||
/* Read out the conventional OOB. */
|
||||
nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
|
||||
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
/*
|
||||
* Now, we want to make sure the block mark is correct. In the
|
||||
|
@ -1345,15 +1340,15 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
if (GPMI_IS_MX23(this)) {
|
||||
/* Read the block mark into the first byte of the OOB buffer. */
|
||||
nand_read_page_op(chip, page, 0, NULL, 0);
|
||||
chip->oob_poi[0] = chip->read_byte(mtd);
|
||||
chip->oob_poi[0] = chip->legacy.read_byte(chip);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
|
||||
static int gpmi_ecc_write_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct mtd_oob_region of = { };
|
||||
|
||||
/* Do we have available oob area? */
|
||||
|
@ -1380,10 +1375,10 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
|
|||
* See set_geometry_by_ecc_info inline comments to have a full description
|
||||
* of the layout used by the GPMI controller.
|
||||
*/
|
||||
static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t *buf,
|
||||
static int gpmi_ecc_read_page_raw(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
struct bch_geometry *nfc_geo = &this->bch_geometry;
|
||||
int eccsize = nfc_geo->ecc_chunk_size;
|
||||
|
@ -1464,11 +1459,10 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
|
|||
* See set_geometry_by_ecc_info inline comments to have a full description
|
||||
* of the layout used by the GPMI controller.
|
||||
*/
|
||||
static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
const uint8_t *buf,
|
||||
static int gpmi_ecc_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
struct bch_geometry *nfc_geo = &this->bch_geometry;
|
||||
int eccsize = nfc_geo->ecc_chunk_size;
|
||||
|
@ -1536,28 +1530,26 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
|
|||
mtd->writesize + mtd->oobsize);
|
||||
}
|
||||
|
||||
static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int gpmi_ecc_read_oob_raw(struct nand_chip *chip, int page)
|
||||
{
|
||||
return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page);
|
||||
return gpmi_ecc_read_page_raw(chip, NULL, 1, page);
|
||||
}
|
||||
|
||||
static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int gpmi_ecc_write_oob_raw(struct nand_chip *chip, int page)
|
||||
{
|
||||
return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page);
|
||||
return gpmi_ecc_write_page_raw(chip, NULL, 1, page);
|
||||
}
|
||||
|
||||
static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
static int gpmi_block_markbad(struct nand_chip *chip, loff_t ofs)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct gpmi_nand_data *this = nand_get_controller_data(chip);
|
||||
int ret = 0;
|
||||
uint8_t *block_mark;
|
||||
int column, page, chipnr;
|
||||
|
||||
chipnr = (int)(ofs >> chip->chip_shift);
|
||||
chip->select_chip(mtd, chipnr);
|
||||
chip->select_chip(chip, chipnr);
|
||||
|
||||
column = !GPMI_IS_MX23(this) ? mtd->writesize : 0;
|
||||
|
||||
|
@ -1570,7 +1562,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||
|
||||
ret = nand_prog_page_op(chip, page, column, block_mark, 1);
|
||||
|
||||
chip->select_chip(mtd, -1);
|
||||
chip->select_chip(chip, -1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1607,7 +1599,6 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
|
|||
struct boot_rom_geometry *rom_geo = &this->rom_geometry;
|
||||
struct device *dev = this->dev;
|
||||
struct nand_chip *chip = &this->nand;
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
unsigned int search_area_size_in_strides;
|
||||
unsigned int stride;
|
||||
unsigned int page;
|
||||
|
@ -1619,7 +1610,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
|
|||
search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent;
|
||||
|
||||
saved_chip_number = this->current_chip;
|
||||
chip->select_chip(mtd, 0);
|
||||
chip->select_chip(chip, 0);
|
||||
|
||||
/*
|
||||
* Loop through the first search area, looking for the NCB fingerprint.
|
||||
|
@ -1637,7 +1628,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
|
|||
* and starts in the 12th byte of the page.
|
||||
*/
|
||||
nand_read_page_op(chip, page, 12, NULL, 0);
|
||||
chip->read_buf(mtd, buffer, strlen(fingerprint));
|
||||
chip->legacy.read_buf(chip, buffer, strlen(fingerprint));
|
||||
|
||||
/* Look for the fingerprint. */
|
||||
if (!memcmp(buffer, fingerprint, strlen(fingerprint))) {
|
||||
|
@ -1647,7 +1638,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this)
|
|||
|
||||
}
|
||||
|
||||
chip->select_chip(mtd, saved_chip_number);
|
||||
chip->select_chip(chip, saved_chip_number);
|
||||
|
||||
if (found_an_ncb_fingerprint)
|
||||
dev_dbg(dev, "\tFound a fingerprint\n");
|
||||
|
@ -1690,7 +1681,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
|
|||
|
||||
/* Select chip 0. */
|
||||
saved_chip_number = this->current_chip;
|
||||
chip->select_chip(mtd, 0);
|
||||
chip->select_chip(chip, 0);
|
||||
|
||||
/* Loop over blocks in the first search area, erasing them. */
|
||||
dev_dbg(dev, "Erasing the search area...\n");
|
||||
|
@ -1716,13 +1707,13 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
|
|||
/* Write the first page of the current stride. */
|
||||
dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
|
||||
|
||||
status = chip->ecc.write_page_raw(mtd, chip, buffer, 0, page);
|
||||
status = chip->ecc.write_page_raw(chip, buffer, 0, page);
|
||||
if (status)
|
||||
dev_err(dev, "[%s] Write failed.\n", __func__);
|
||||
}
|
||||
|
||||
/* Deselect chip 0. */
|
||||
chip->select_chip(mtd, saved_chip_number);
|
||||
chip->select_chip(chip, saved_chip_number);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1771,10 +1762,10 @@ static int mx23_boot_init(struct gpmi_nand_data *this)
|
|||
byte = block << chip->phys_erase_shift;
|
||||
|
||||
/* Send the command to read the conventional block mark. */
|
||||
chip->select_chip(mtd, chipnr);
|
||||
chip->select_chip(chip, chipnr);
|
||||
nand_read_page_op(chip, page, mtd->writesize, NULL, 0);
|
||||
block_mark = chip->read_byte(mtd);
|
||||
chip->select_chip(mtd, -1);
|
||||
block_mark = chip->legacy.read_byte(chip);
|
||||
chip->select_chip(chip, -1);
|
||||
|
||||
/*
|
||||
* Check if the block is marked bad. If so, we need to mark it
|
||||
|
@ -1783,7 +1774,7 @@ static int mx23_boot_init(struct gpmi_nand_data *this)
|
|||
*/
|
||||
if (block_mark != 0xff) {
|
||||
dev_dbg(dev, "Transcribing mark in block %u\n", block);
|
||||
ret = chip->block_markbad(mtd, byte);
|
||||
ret = chip->legacy.block_markbad(chip, byte);
|
||||
if (ret)
|
||||
dev_err(dev,
|
||||
"Failed to mark block bad with ret %d\n",
|
||||
|
@ -1911,13 +1902,13 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
|
|||
nand_set_flash_node(chip, this->pdev->dev.of_node);
|
||||
chip->select_chip = gpmi_select_chip;
|
||||
chip->setup_data_interface = gpmi_setup_data_interface;
|
||||
chip->cmd_ctrl = gpmi_cmd_ctrl;
|
||||
chip->dev_ready = gpmi_dev_ready;
|
||||
chip->read_byte = gpmi_read_byte;
|
||||
chip->read_buf = gpmi_read_buf;
|
||||
chip->write_buf = gpmi_write_buf;
|
||||
chip->legacy.cmd_ctrl = gpmi_cmd_ctrl;
|
||||
chip->legacy.dev_ready = gpmi_dev_ready;
|
||||
chip->legacy.read_byte = gpmi_read_byte;
|
||||
chip->legacy.read_buf = gpmi_read_buf;
|
||||
chip->legacy.write_buf = gpmi_write_buf;
|
||||
chip->badblock_pattern = &gpmi_bbt_descr;
|
||||
chip->block_markbad = gpmi_block_markbad;
|
||||
chip->legacy.block_markbad = gpmi_block_markbad;
|
||||
chip->options |= NAND_NO_SUBPAGE_WRITE;
|
||||
|
||||
/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
|
||||
|
@ -1934,7 +1925,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
|
|||
goto err_out;
|
||||
|
||||
chip->dummy_controller.ops = &gpmi_nand_controller_ops;
|
||||
ret = nand_scan(mtd, GPMI_IS_MX6(this) ? 2 : 1);
|
||||
ret = nand_scan(chip, GPMI_IS_MX6(this) ? 2 : 1);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
|
@ -2026,7 +2017,7 @@ static int gpmi_nand_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct gpmi_nand_data *this = platform_get_drvdata(pdev);
|
||||
|
||||
nand_release(nand_to_mtd(&this->nand));
|
||||
nand_release(&this->nand);
|
||||
gpmi_free_dma_buffer(this);
|
||||
release_resources(this);
|
||||
return 0;
|
||||
|
|
|
@ -178,7 +178,7 @@ int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
|
|||
int gpmi_send_command(struct gpmi_nand_data *);
|
||||
int gpmi_enable_clk(struct gpmi_nand_data *this);
|
||||
int gpmi_disable_clk(struct gpmi_nand_data *this);
|
||||
int gpmi_setup_data_interface(struct mtd_info *mtd, int chipnr,
|
||||
int gpmi_setup_data_interface(struct nand_chip *chip, int chipnr,
|
||||
const struct nand_data_interface *conf);
|
||||
void gpmi_nfc_apply_timings(struct gpmi_nand_data *this);
|
||||
int gpmi_read_data(struct gpmi_nand_data *, void *buf, int len);
|
||||
|
|
|
@ -353,9 +353,8 @@ static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
|
||||
static void hisi_nfc_select_chip(struct nand_chip *chip, int chipselect)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct hinfc_host *host = nand_get_controller_data(chip);
|
||||
|
||||
if (chipselect < 0)
|
||||
|
@ -364,9 +363,8 @@ static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
|
|||
host->chipselect = chipselect;
|
||||
}
|
||||
|
||||
static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t hisi_nfc_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct hinfc_host *host = nand_get_controller_data(chip);
|
||||
|
||||
if (host->command == NAND_CMD_STATUS)
|
||||
|
@ -380,28 +378,17 @@ static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
|
|||
return *(uint8_t *)(host->buffer + host->offset - 1);
|
||||
}
|
||||
|
||||
static u16 hisi_nfc_read_word(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct hinfc_host *host = nand_get_controller_data(chip);
|
||||
|
||||
host->offset += 2;
|
||||
return *(u16 *)(host->buffer + host->offset - 2);
|
||||
}
|
||||
|
||||
static void
|
||||
hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
hisi_nfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct hinfc_host *host = nand_get_controller_data(chip);
|
||||
|
||||
memcpy(host->buffer + host->offset, buf, len);
|
||||
host->offset += len;
|
||||
}
|
||||
|
||||
static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void hisi_nfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct hinfc_host *host = nand_get_controller_data(chip);
|
||||
|
||||
memcpy(buf, host->buffer + host->offset, len);
|
||||
|
@ -442,10 +429,10 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr)
|
|||
}
|
||||
}
|
||||
|
||||
static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
|
||||
int page_addr)
|
||||
static void hisi_nfc_cmdfunc(struct nand_chip *chip, unsigned command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct hinfc_host *host = nand_get_controller_data(chip);
|
||||
int is_cache_invalid = 1;
|
||||
unsigned int flag = 0;
|
||||
|
@ -537,15 +524,16 @@ static irqreturn_t hinfc_irq_handle(int irq, void *devid)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
|
||||
static int hisi_nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct hinfc_host *host = nand_get_controller_data(chip);
|
||||
int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc;
|
||||
int stat_1, stat_2;
|
||||
|
||||
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
|
||||
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
/* errors which can not be corrected by ECC */
|
||||
if (host->irq_status & HINFC504_INTS_UE) {
|
||||
|
@ -569,9 +557,9 @@ static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
|
|||
return max_bitflips;
|
||||
}
|
||||
|
||||
static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int hisi_nand_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct hinfc_host *host = nand_get_controller_data(chip);
|
||||
|
||||
nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
|
||||
|
@ -585,13 +573,15 @@ static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf, int oob_required,
|
||||
static int hisi_nand_write_page_hwecc(struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
|
||||
if (oob_required)
|
||||
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
@ -792,15 +782,14 @@ static int hisi_nfc_probe(struct platform_device *pdev)
|
|||
|
||||
nand_set_controller_data(chip, host);
|
||||
nand_set_flash_node(chip, np);
|
||||
chip->cmdfunc = hisi_nfc_cmdfunc;
|
||||
chip->legacy.cmdfunc = hisi_nfc_cmdfunc;
|
||||
chip->select_chip = hisi_nfc_select_chip;
|
||||
chip->read_byte = hisi_nfc_read_byte;
|
||||
chip->read_word = hisi_nfc_read_word;
|
||||
chip->write_buf = hisi_nfc_write_buf;
|
||||
chip->read_buf = hisi_nfc_read_buf;
|
||||
chip->chip_delay = HINFC504_CHIP_DELAY;
|
||||
chip->set_features = nand_get_set_features_notsupp;
|
||||
chip->get_features = nand_get_set_features_notsupp;
|
||||
chip->legacy.read_byte = hisi_nfc_read_byte;
|
||||
chip->legacy.write_buf = hisi_nfc_write_buf;
|
||||
chip->legacy.read_buf = hisi_nfc_read_buf;
|
||||
chip->legacy.chip_delay = HINFC504_CHIP_DELAY;
|
||||
chip->legacy.set_features = nand_get_set_features_notsupp;
|
||||
chip->legacy.get_features = nand_get_set_features_notsupp;
|
||||
|
||||
hisi_nfc_host_init(host);
|
||||
|
||||
|
@ -811,7 +800,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
chip->dummy_controller.ops = &hisi_nfc_controller_ops;
|
||||
ret = nand_scan(mtd, max_chips);
|
||||
ret = nand_scan(chip, max_chips);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -828,9 +817,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
|
|||
static int hisi_nfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hinfc_host *host = platform_get_drvdata(pdev);
|
||||
struct mtd_info *mtd = nand_to_mtd(&host->chip);
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(&host->chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
115
drivers/mtd/nand/raw/internals.h
Normal file
115
drivers/mtd/nand/raw/internals.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2018 - Bootlin
|
||||
*
|
||||
* Author: Boris Brezillon <boris.brezillon@bootlin.com>
|
||||
*
|
||||
* Header containing internal definitions to be used only by core files.
|
||||
* NAND controller drivers should not include this file.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RAWNAND_INTERNALS
|
||||
#define __LINUX_RAWNAND_INTERNALS
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
||||
/*
|
||||
* NAND Flash Manufacturer ID Codes
|
||||
*/
|
||||
#define NAND_MFR_AMD 0x01
|
||||
#define NAND_MFR_ATO 0x9b
|
||||
#define NAND_MFR_EON 0x92
|
||||
#define NAND_MFR_ESMT 0xc8
|
||||
#define NAND_MFR_FUJITSU 0x04
|
||||
#define NAND_MFR_HYNIX 0xad
|
||||
#define NAND_MFR_INTEL 0x89
|
||||
#define NAND_MFR_MACRONIX 0xc2
|
||||
#define NAND_MFR_MICRON 0x2c
|
||||
#define NAND_MFR_NATIONAL 0x8f
|
||||
#define NAND_MFR_RENESAS 0x07
|
||||
#define NAND_MFR_SAMSUNG 0xec
|
||||
#define NAND_MFR_SANDISK 0x45
|
||||
#define NAND_MFR_STMICRO 0x20
|
||||
#define NAND_MFR_TOSHIBA 0x98
|
||||
#define NAND_MFR_WINBOND 0xef
|
||||
|
||||
/**
|
||||
* struct nand_manufacturer_ops - NAND Manufacturer operations
|
||||
* @detect: detect the NAND memory organization and capabilities
|
||||
* @init: initialize all vendor specific fields (like the ->read_retry()
|
||||
* implementation) if any.
|
||||
* @cleanup: the ->init() function may have allocated resources, ->cleanup()
|
||||
* is here to let vendor specific code release those resources.
|
||||
* @fixup_onfi_param_page: apply vendor specific fixups to the ONFI parameter
|
||||
* page. This is called after the checksum is verified.
|
||||
*/
|
||||
struct nand_manufacturer_ops {
|
||||
void (*detect)(struct nand_chip *chip);
|
||||
int (*init)(struct nand_chip *chip);
|
||||
void (*cleanup)(struct nand_chip *chip);
|
||||
void (*fixup_onfi_param_page)(struct nand_chip *chip,
|
||||
struct nand_onfi_params *p);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nand_manufacturer - NAND Flash Manufacturer structure
|
||||
* @name: Manufacturer name
|
||||
* @id: manufacturer ID code of device.
|
||||
* @ops: manufacturer operations
|
||||
*/
|
||||
struct nand_manufacturer {
|
||||
int id;
|
||||
char *name;
|
||||
const struct nand_manufacturer_ops *ops;
|
||||
};
|
||||
|
||||
|
||||
extern struct nand_flash_dev nand_flash_ids[];
|
||||
|
||||
extern const struct nand_manufacturer_ops amd_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops esmt_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops hynix_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops macronix_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops micron_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops samsung_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops;
|
||||
|
||||
/* Core functions */
|
||||
const struct nand_manufacturer *nand_get_manufacturer(u8 id);
|
||||
int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs);
|
||||
int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
|
||||
int allowbbt);
|
||||
int onfi_fill_data_interface(struct nand_chip *chip,
|
||||
enum nand_data_interface_type type,
|
||||
int timing_mode);
|
||||
int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
|
||||
int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
|
||||
int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf,
|
||||
int oob_required, int page);
|
||||
int nand_write_page_raw_notsupp(struct nand_chip *chip, const u8 *buf,
|
||||
int oob_required, int page);
|
||||
int nand_exit_status_op(struct nand_chip *chip);
|
||||
int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
|
||||
unsigned int len);
|
||||
void nand_decode_ext_id(struct nand_chip *chip);
|
||||
void panic_nand_wait(struct nand_chip *chip, unsigned long timeo);
|
||||
void sanitize_string(uint8_t *s, size_t len);
|
||||
|
||||
/* BBT functions */
|
||||
int nand_markbad_bbt(struct nand_chip *chip, loff_t offs);
|
||||
int nand_isreserved_bbt(struct nand_chip *chip, loff_t offs);
|
||||
int nand_isbad_bbt(struct nand_chip *chip, loff_t offs, int allowbbt);
|
||||
|
||||
/* Legacy */
|
||||
void nand_legacy_set_defaults(struct nand_chip *chip);
|
||||
void nand_legacy_adjust_cmdfunc(struct nand_chip *chip);
|
||||
int nand_legacy_check_hooks(struct nand_chip *chip);
|
||||
|
||||
/* ONFI functions */
|
||||
u16 onfi_crc16(u16 crc, u8 const *p, size_t len);
|
||||
int nand_onfi_detect(struct nand_chip *chip);
|
||||
|
||||
/* JEDEC functions */
|
||||
int nand_jedec_detect(struct nand_chip *chip);
|
||||
|
||||
#endif /* __LINUX_RAWNAND_INTERNALS */
|
|
@ -78,10 +78,9 @@ static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
|
|||
return container_of(mtd_to_nand(mtd), struct jz_nand, chip);
|
||||
}
|
||||
|
||||
static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
|
||||
static void jz_nand_select_chip(struct nand_chip *chip, int chipnr)
|
||||
{
|
||||
struct jz_nand *nand = mtd_to_jz_nand(mtd);
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
|
||||
uint32_t ctrl;
|
||||
int banknr;
|
||||
|
||||
|
@ -92,18 +91,18 @@ static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
|
|||
banknr = -1;
|
||||
} else {
|
||||
banknr = nand->banks[chipnr] - 1;
|
||||
chip->IO_ADDR_R = nand->bank_base[banknr];
|
||||
chip->IO_ADDR_W = nand->bank_base[banknr];
|
||||
chip->legacy.IO_ADDR_R = nand->bank_base[banknr];
|
||||
chip->legacy.IO_ADDR_W = nand->bank_base[banknr];
|
||||
}
|
||||
writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
|
||||
|
||||
nand->selected_bank = banknr;
|
||||
}
|
||||
|
||||
static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
|
||||
static void jz_nand_cmd_ctrl(struct nand_chip *chip, int dat,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct jz_nand *nand = mtd_to_jz_nand(mtd);
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
|
||||
uint32_t reg;
|
||||
void __iomem *bank_base = nand->bank_base[nand->selected_bank];
|
||||
|
||||
|
@ -115,7 +114,7 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
|
|||
bank_base += JZ_NAND_MEM_ADDR_OFFSET;
|
||||
else if (ctrl & NAND_CLE)
|
||||
bank_base += JZ_NAND_MEM_CMD_OFFSET;
|
||||
chip->IO_ADDR_W = bank_base;
|
||||
chip->legacy.IO_ADDR_W = bank_base;
|
||||
|
||||
reg = readl(nand->base + JZ_REG_NAND_CTRL);
|
||||
if (ctrl & NAND_NCE)
|
||||
|
@ -125,18 +124,18 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
|
|||
writel(reg, nand->base + JZ_REG_NAND_CTRL);
|
||||
}
|
||||
if (dat != NAND_CMD_NONE)
|
||||
writeb(dat, chip->IO_ADDR_W);
|
||||
writeb(dat, chip->legacy.IO_ADDR_W);
|
||||
}
|
||||
|
||||
static int jz_nand_dev_ready(struct mtd_info *mtd)
|
||||
static int jz_nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct jz_nand *nand = mtd_to_jz_nand(mtd);
|
||||
struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
|
||||
return gpiod_get_value_cansleep(nand->busy_gpio);
|
||||
}
|
||||
|
||||
static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
|
||||
static void jz_nand_hwctl(struct nand_chip *chip, int mode)
|
||||
{
|
||||
struct jz_nand *nand = mtd_to_jz_nand(mtd);
|
||||
struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
|
||||
uint32_t reg;
|
||||
|
||||
writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
|
||||
|
@ -162,10 +161,10 @@ static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
|
|||
writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
|
||||
}
|
||||
|
||||
static int jz_nand_calculate_ecc_rs(struct mtd_info *mtd, const uint8_t *dat,
|
||||
static int jz_nand_calculate_ecc_rs(struct nand_chip *chip, const uint8_t *dat,
|
||||
uint8_t *ecc_code)
|
||||
{
|
||||
struct jz_nand *nand = mtd_to_jz_nand(mtd);
|
||||
struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
|
||||
uint32_t reg, status;
|
||||
int i;
|
||||
unsigned int timeout = 1000;
|
||||
|
@ -215,10 +214,10 @@ static void jz_nand_correct_data(uint8_t *dat, int index, int mask)
|
|||
dat[index+1] = (data >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
|
||||
static int jz_nand_correct_ecc_rs(struct nand_chip *chip, uint8_t *dat,
|
||||
uint8_t *read_ecc, uint8_t *calc_ecc)
|
||||
{
|
||||
struct jz_nand *nand = mtd_to_jz_nand(mtd);
|
||||
struct jz_nand *nand = mtd_to_jz_nand(nand_to_mtd(chip));
|
||||
int i, error_count, index;
|
||||
uint32_t reg, status, error;
|
||||
unsigned int timeout = 1000;
|
||||
|
@ -331,19 +330,19 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
|
|||
|
||||
if (chipnr == 0) {
|
||||
/* Detect first chip. */
|
||||
ret = nand_scan(mtd, 1);
|
||||
ret = nand_scan(chip, 1);
|
||||
if (ret)
|
||||
goto notfound_id;
|
||||
|
||||
/* Retrieve the IDs from the first chip. */
|
||||
chip->select_chip(mtd, 0);
|
||||
chip->select_chip(chip, 0);
|
||||
nand_reset_op(chip);
|
||||
nand_readid_op(chip, 0, id, sizeof(id));
|
||||
*nand_maf_id = id[0];
|
||||
*nand_dev_id = id[1];
|
||||
} else {
|
||||
/* Detect additional chip. */
|
||||
chip->select_chip(mtd, chipnr);
|
||||
chip->select_chip(chip, chipnr);
|
||||
nand_reset_op(chip);
|
||||
nand_readid_op(chip, 0, id, sizeof(id));
|
||||
if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) {
|
||||
|
@ -426,13 +425,13 @@ static int jz_nand_probe(struct platform_device *pdev)
|
|||
chip->ecc.strength = 4;
|
||||
chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
|
||||
|
||||
chip->chip_delay = 50;
|
||||
chip->cmd_ctrl = jz_nand_cmd_ctrl;
|
||||
chip->legacy.chip_delay = 50;
|
||||
chip->legacy.cmd_ctrl = jz_nand_cmd_ctrl;
|
||||
chip->select_chip = jz_nand_select_chip;
|
||||
chip->dummy_controller.ops = &jz_nand_controller_ops;
|
||||
|
||||
if (nand->busy_gpio)
|
||||
chip->dev_ready = jz_nand_dev_ready;
|
||||
chip->legacy.dev_ready = jz_nand_dev_ready;
|
||||
|
||||
platform_set_drvdata(pdev, nand);
|
||||
|
||||
|
@ -507,7 +506,7 @@ static int jz_nand_remove(struct platform_device *pdev)
|
|||
struct jz_nand *nand = platform_get_drvdata(pdev);
|
||||
size_t i;
|
||||
|
||||
nand_release(nand_to_mtd(&nand->chip));
|
||||
nand_release(&nand->chip);
|
||||
|
||||
/* Deassert and disable all chips */
|
||||
writel(0, nand->base + JZ_REG_NAND_CTRL);
|
||||
|
|
|
@ -71,9 +71,9 @@ static inline struct jz4780_nand_controller
|
|||
return container_of(ctrl, struct jz4780_nand_controller, controller);
|
||||
}
|
||||
|
||||
static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
|
||||
static void jz4780_nand_select_chip(struct nand_chip *chip, int chipnr)
|
||||
{
|
||||
struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
|
||||
struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
|
||||
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
|
||||
struct jz4780_nand_cs *cs;
|
||||
|
||||
|
@ -86,10 +86,10 @@ static void jz4780_nand_select_chip(struct mtd_info *mtd, int chipnr)
|
|||
nfc->selected = chipnr;
|
||||
}
|
||||
|
||||
static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
static void jz4780_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
|
||||
struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
|
||||
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
|
||||
struct jz4780_nand_cs *cs;
|
||||
|
||||
|
@ -109,24 +109,24 @@ static void jz4780_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
|||
writeb(cmd, cs->base + OFFSET_CMD);
|
||||
}
|
||||
|
||||
static int jz4780_nand_dev_ready(struct mtd_info *mtd)
|
||||
static int jz4780_nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
|
||||
struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
|
||||
|
||||
return !gpiod_get_value_cansleep(nand->busy_gpio);
|
||||
}
|
||||
|
||||
static void jz4780_nand_ecc_hwctl(struct mtd_info *mtd, int mode)
|
||||
static void jz4780_nand_ecc_hwctl(struct nand_chip *chip, int mode)
|
||||
{
|
||||
struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
|
||||
struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
|
||||
|
||||
nand->reading = (mode == NAND_ECC_READ);
|
||||
}
|
||||
|
||||
static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
|
||||
static int jz4780_nand_ecc_calculate(struct nand_chip *chip, const u8 *dat,
|
||||
u8 *ecc_code)
|
||||
{
|
||||
struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
|
||||
struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
|
||||
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
|
||||
struct jz4780_bch_params params;
|
||||
|
||||
|
@ -144,10 +144,10 @@ static int jz4780_nand_ecc_calculate(struct mtd_info *mtd, const u8 *dat,
|
|||
return jz4780_bch_calculate(nfc->bch, ¶ms, dat, ecc_code);
|
||||
}
|
||||
|
||||
static int jz4780_nand_ecc_correct(struct mtd_info *mtd, u8 *dat,
|
||||
static int jz4780_nand_ecc_correct(struct nand_chip *chip, u8 *dat,
|
||||
u8 *read_ecc, u8 *calc_ecc)
|
||||
{
|
||||
struct jz4780_nand_chip *nand = to_jz4780_nand_chip(mtd);
|
||||
struct jz4780_nand_chip *nand = to_jz4780_nand_chip(nand_to_mtd(chip));
|
||||
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(nand->chip.controller);
|
||||
struct jz4780_bch_params params;
|
||||
|
||||
|
@ -256,7 +256,7 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
|
|||
dev_err(dev, "failed to request busy GPIO: %d\n", ret);
|
||||
return ret;
|
||||
} else if (nand->busy_gpio) {
|
||||
nand->chip.dev_ready = jz4780_nand_dev_ready;
|
||||
nand->chip.legacy.dev_ready = jz4780_nand_dev_ready;
|
||||
}
|
||||
|
||||
nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
|
||||
|
@ -275,24 +275,24 @@ static int jz4780_nand_init_chip(struct platform_device *pdev,
|
|||
return -ENOMEM;
|
||||
mtd->dev.parent = dev;
|
||||
|
||||
chip->IO_ADDR_R = cs->base + OFFSET_DATA;
|
||||
chip->IO_ADDR_W = cs->base + OFFSET_DATA;
|
||||
chip->chip_delay = RB_DELAY_US;
|
||||
chip->legacy.IO_ADDR_R = cs->base + OFFSET_DATA;
|
||||
chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA;
|
||||
chip->legacy.chip_delay = RB_DELAY_US;
|
||||
chip->options = NAND_NO_SUBPAGE_WRITE;
|
||||
chip->select_chip = jz4780_nand_select_chip;
|
||||
chip->cmd_ctrl = jz4780_nand_cmd_ctrl;
|
||||
chip->legacy.cmd_ctrl = jz4780_nand_cmd_ctrl;
|
||||
chip->ecc.mode = NAND_ECC_HW;
|
||||
chip->controller = &nfc->controller;
|
||||
nand_set_flash_node(chip, np);
|
||||
|
||||
chip->controller->ops = &jz4780_nand_controller_ops;
|
||||
ret = nand_scan(mtd, 1);
|
||||
ret = nand_scan(chip, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mtd_device_register(mtd, NULL, 0);
|
||||
if (ret) {
|
||||
nand_release(mtd);
|
||||
nand_release(chip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ static void jz4780_nand_cleanup_chips(struct jz4780_nand_controller *nfc)
|
|||
|
||||
while (!list_empty(&nfc->chips)) {
|
||||
chip = list_first_entry(&nfc->chips, struct jz4780_nand_chip, chip_list);
|
||||
nand_release(nand_to_mtd(&chip->chip));
|
||||
nand_release(&chip->chip);
|
||||
list_del(&chip->chip_list);
|
||||
}
|
||||
}
|
||||
|
@ -352,7 +352,7 @@ static int jz4780_nand_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
nfc = devm_kzalloc(dev, sizeof(*nfc) + (sizeof(nfc->cs[0]) * num_banks), GFP_KERNEL);
|
||||
nfc = devm_kzalloc(dev, struct_size(nfc, cs, num_banks), GFP_KERNEL);
|
||||
if (!nfc)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -286,10 +286,9 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
|
|||
/*
|
||||
* Hardware specific access to control lines
|
||||
*/
|
||||
static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
static void lpc32xx_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
|
||||
if (cmd != NAND_CMD_NONE) {
|
||||
|
@ -303,9 +302,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
|||
/*
|
||||
* Read Device Ready (NAND device _and_ controller ready)
|
||||
*/
|
||||
static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
|
||||
static int lpc32xx_nand_device_ready(struct nand_chip *nand_chip)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
|
||||
if ((readb(MLC_ISR(host->io_base)) &
|
||||
|
@ -330,8 +328,9 @@ static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
static int lpc32xx_waitfunc_nand(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
|
||||
|
||||
if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)
|
||||
|
@ -349,9 +348,9 @@ exit:
|
|||
return NAND_STATUS_READY;
|
||||
}
|
||||
|
||||
static int lpc32xx_waitfunc_controller(struct mtd_info *mtd,
|
||||
struct nand_chip *chip)
|
||||
static int lpc32xx_waitfunc_controller(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
|
||||
|
||||
if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY)
|
||||
|
@ -369,10 +368,10 @@ exit:
|
|||
return NAND_STATUS_READY;
|
||||
}
|
||||
|
||||
static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
static int lpc32xx_waitfunc(struct nand_chip *chip)
|
||||
{
|
||||
lpc32xx_waitfunc_nand(mtd, chip);
|
||||
lpc32xx_waitfunc_controller(mtd, chip);
|
||||
lpc32xx_waitfunc_nand(chip);
|
||||
lpc32xx_waitfunc_controller(chip);
|
||||
|
||||
return NAND_STATUS_READY;
|
||||
}
|
||||
|
@ -442,9 +441,10 @@ out1:
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int lpc32xx_read_page(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
|
||||
int i, j;
|
||||
uint8_t *oobbuf = chip->oob_poi;
|
||||
|
@ -470,7 +470,7 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base));
|
||||
|
||||
/* Wait for Controller Ready */
|
||||
lpc32xx_waitfunc_controller(mtd, chip);
|
||||
lpc32xx_waitfunc_controller(chip);
|
||||
|
||||
/* Check ECC Error status */
|
||||
mlc_isr = readl(MLC_ISR(host->io_base));
|
||||
|
@ -507,11 +507,11 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int lpc32xx_write_page_lowlevel(struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
|
||||
const uint8_t *oobbuf = chip->oob_poi;
|
||||
uint8_t *dma_buf = (uint8_t *)buf;
|
||||
|
@ -551,32 +551,30 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
|
|||
writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base));
|
||||
|
||||
/* Wait for Controller Ready */
|
||||
lpc32xx_waitfunc_controller(mtd, chip);
|
||||
lpc32xx_waitfunc_controller(chip);
|
||||
}
|
||||
|
||||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int lpc32xx_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
|
||||
|
||||
/* Read whole page - necessary with MLC controller! */
|
||||
lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page);
|
||||
lpc32xx_read_page(chip, host->dummy_buf, 1, page);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int lpc32xx_write_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
/* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */
|
||||
static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
|
||||
static void lpc32xx_ecc_enable(struct nand_chip *chip, int mode)
|
||||
{
|
||||
/* Always enabled! */
|
||||
}
|
||||
|
@ -741,11 +739,11 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
|||
if (res)
|
||||
goto put_clk;
|
||||
|
||||
nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
|
||||
nand_chip->dev_ready = lpc32xx_nand_device_ready;
|
||||
nand_chip->chip_delay = 25; /* us */
|
||||
nand_chip->IO_ADDR_R = MLC_DATA(host->io_base);
|
||||
nand_chip->IO_ADDR_W = MLC_DATA(host->io_base);
|
||||
nand_chip->legacy.cmd_ctrl = lpc32xx_nand_cmd_ctrl;
|
||||
nand_chip->legacy.dev_ready = lpc32xx_nand_device_ready;
|
||||
nand_chip->legacy.chip_delay = 25; /* us */
|
||||
nand_chip->legacy.IO_ADDR_R = MLC_DATA(host->io_base);
|
||||
nand_chip->legacy.IO_ADDR_W = MLC_DATA(host->io_base);
|
||||
|
||||
/* Init NAND controller */
|
||||
lpc32xx_nand_setup(host);
|
||||
|
@ -762,7 +760,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
|||
nand_chip->ecc.read_oob = lpc32xx_read_oob;
|
||||
nand_chip->ecc.strength = 4;
|
||||
nand_chip->ecc.bytes = 10;
|
||||
nand_chip->waitfunc = lpc32xx_waitfunc;
|
||||
nand_chip->legacy.waitfunc = lpc32xx_waitfunc;
|
||||
|
||||
nand_chip->options = NAND_NO_SUBPAGE_WRITE;
|
||||
nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
|
||||
|
@ -802,7 +800,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
|||
* SMALL block or LARGE block.
|
||||
*/
|
||||
nand_chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
|
||||
res = nand_scan(mtd, 1);
|
||||
res = nand_scan(nand_chip, 1);
|
||||
if (res)
|
||||
goto free_irq;
|
||||
|
||||
|
@ -839,9 +837,8 @@ free_gpio:
|
|||
static int lpc32xx_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
|
||||
struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(&host->nand_chip);
|
||||
free_irq(host->irq, host);
|
||||
if (use_dma)
|
||||
dma_release_channel(host->dma_chan);
|
||||
|
|
|
@ -278,11 +278,10 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
|
|||
/*
|
||||
* Hardware specific access to control lines
|
||||
*/
|
||||
static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
static void lpc32xx_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
uint32_t tmp;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
|
||||
|
||||
/* Does CE state need to be changed? */
|
||||
|
@ -304,9 +303,8 @@ static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
|||
/*
|
||||
* Read the Device Ready pin
|
||||
*/
|
||||
static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
|
||||
static int lpc32xx_nand_device_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
|
||||
int rdy = 0;
|
||||
|
||||
|
@ -337,7 +335,7 @@ static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
|
|||
/*
|
||||
* Prepares SLC for transfers with H/W ECC enabled
|
||||
*/
|
||||
static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
|
||||
static void lpc32xx_nand_ecc_enable(struct nand_chip *chip, int mode)
|
||||
{
|
||||
/* Hardware ECC is enabled automatically in hardware as needed */
|
||||
}
|
||||
|
@ -345,7 +343,7 @@ static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
|
|||
/*
|
||||
* Calculates the ECC for the data
|
||||
*/
|
||||
static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
|
||||
static int lpc32xx_nand_ecc_calculate(struct nand_chip *chip,
|
||||
const unsigned char *buf,
|
||||
unsigned char *code)
|
||||
{
|
||||
|
@ -359,9 +357,8 @@ static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
|
|||
/*
|
||||
* Read a single byte from NAND device
|
||||
*/
|
||||
static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t lpc32xx_nand_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
|
||||
|
||||
return (uint8_t)readl(SLC_DATA(host->io_base));
|
||||
|
@ -370,9 +367,8 @@ static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
|
|||
/*
|
||||
* Simple device read without ECC
|
||||
*/
|
||||
static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void lpc32xx_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
|
||||
|
||||
/* Direct device read with no ECC */
|
||||
|
@ -383,9 +379,9 @@ static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
|||
/*
|
||||
* Simple device write without ECC
|
||||
*/
|
||||
static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
static void lpc32xx_nand_write_buf(struct nand_chip *chip, const uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
|
||||
|
||||
/* Direct device write with no ECC */
|
||||
|
@ -396,18 +392,20 @@ static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int
|
|||
/*
|
||||
* Read the OOB data from the device without ECC using FIFO method
|
||||
*/
|
||||
static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, int page)
|
||||
static int lpc32xx_nand_read_oob_syndrome(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the OOB data to the device without ECC using FIFO method
|
||||
*/
|
||||
static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, int page)
|
||||
static int lpc32xx_nand_write_oob_syndrome(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
return nand_prog_page_op(chip, page, mtd->writesize, chip->oob_poi,
|
||||
mtd->oobsize);
|
||||
}
|
||||
|
@ -610,10 +608,10 @@ static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
|
|||
* Read the data and OOB data from the device, use ECC correction with the
|
||||
* data, disable ECC for the OOB data
|
||||
*/
|
||||
static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t *buf,
|
||||
static int lpc32xx_nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
|
||||
struct mtd_oob_region oobregion = { };
|
||||
int stat, i, status, error;
|
||||
|
@ -626,7 +624,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
|
|||
status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
|
||||
|
||||
/* Get OOB data */
|
||||
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
/* Convert to stored ECC format */
|
||||
lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps);
|
||||
|
@ -639,7 +637,7 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
|
|||
oobecc = chip->oob_poi + oobregion.offset;
|
||||
|
||||
for (i = 0; i < chip->ecc.steps; i++) {
|
||||
stat = chip->ecc.correct(mtd, buf, oobecc,
|
||||
stat = chip->ecc.correct(chip, buf, oobecc,
|
||||
&tmpecc[i * chip->ecc.bytes]);
|
||||
if (stat < 0)
|
||||
mtd->ecc_stats.failed++;
|
||||
|
@ -657,17 +655,18 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
|
|||
* Read the data and OOB data from the device, no ECC correction with the
|
||||
* data or OOB data
|
||||
*/
|
||||
static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int lpc32xx_nand_read_page_raw_syndrome(struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
/* Issue read command */
|
||||
nand_read_page_op(chip, page, 0, NULL, 0);
|
||||
|
||||
/* Raw reads can just use the FIFO interface */
|
||||
chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
|
||||
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
chip->legacy.read_buf(chip, buf, chip->ecc.size * chip->ecc.steps);
|
||||
chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -676,11 +675,11 @@ static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
|
|||
* Write the data and OOB data to the device, use ECC with the data,
|
||||
* disable ECC for the OOB data
|
||||
*/
|
||||
static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int lpc32xx_nand_write_page_syndrome(struct nand_chip *chip,
|
||||
const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct lpc32xx_nand_host *host = nand_get_controller_data(chip);
|
||||
struct mtd_oob_region oobregion = { };
|
||||
uint8_t *pb;
|
||||
|
@ -705,7 +704,7 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
|
|||
lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps);
|
||||
|
||||
/* Write ECC data to device */
|
||||
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
@ -714,15 +713,16 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
|
|||
* Write the data and OOB data to the device, no ECC correction with the
|
||||
* data or OOB data
|
||||
*/
|
||||
static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int lpc32xx_nand_write_page_raw_syndrome(struct nand_chip *chip,
|
||||
const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
/* Raw writes can just use the FIFO interface */
|
||||
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->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
@ -878,11 +878,11 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
|||
goto enable_wp;
|
||||
|
||||
/* Set NAND IO addresses and command/ready functions */
|
||||
chip->IO_ADDR_R = SLC_DATA(host->io_base);
|
||||
chip->IO_ADDR_W = SLC_DATA(host->io_base);
|
||||
chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
|
||||
chip->dev_ready = lpc32xx_nand_device_ready;
|
||||
chip->chip_delay = 20; /* 20us command delay time */
|
||||
chip->legacy.IO_ADDR_R = SLC_DATA(host->io_base);
|
||||
chip->legacy.IO_ADDR_W = SLC_DATA(host->io_base);
|
||||
chip->legacy.cmd_ctrl = lpc32xx_nand_cmd_ctrl;
|
||||
chip->legacy.dev_ready = lpc32xx_nand_device_ready;
|
||||
chip->legacy.chip_delay = 20; /* 20us command delay time */
|
||||
|
||||
/* Init NAND controller */
|
||||
lpc32xx_nand_setup(host);
|
||||
|
@ -891,9 +891,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
|||
|
||||
/* NAND callbacks for LPC32xx SLC hardware */
|
||||
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
|
||||
chip->read_byte = lpc32xx_nand_read_byte;
|
||||
chip->read_buf = lpc32xx_nand_read_buf;
|
||||
chip->write_buf = lpc32xx_nand_write_buf;
|
||||
chip->legacy.read_byte = lpc32xx_nand_read_byte;
|
||||
chip->legacy.read_buf = lpc32xx_nand_read_buf;
|
||||
chip->legacy.write_buf = lpc32xx_nand_write_buf;
|
||||
chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome;
|
||||
chip->ecc.read_page = lpc32xx_nand_read_page_syndrome;
|
||||
chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome;
|
||||
|
@ -925,7 +925,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
|||
|
||||
/* Find NAND device */
|
||||
chip->dummy_controller.ops = &lpc32xx_nand_controller_ops;
|
||||
res = nand_scan(mtd, 1);
|
||||
res = nand_scan(chip, 1);
|
||||
if (res)
|
||||
goto release_dma;
|
||||
|
||||
|
@ -956,9 +956,8 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
|
|||
{
|
||||
uint32_t tmp;
|
||||
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
|
||||
struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(&host->nand_chip);
|
||||
dma_release_channel(host->dma_chan);
|
||||
|
||||
/* Force CE high */
|
||||
|
|
|
@ -5,6 +5,73 @@
|
|||
* Copyright (C) 2017 Marvell
|
||||
* Author: Miquel RAYNAL <miquel.raynal@free-electrons.com>
|
||||
*
|
||||
*
|
||||
* This NAND controller driver handles two versions of the hardware,
|
||||
* one is called NFCv1 and is available on PXA SoCs and the other is
|
||||
* called NFCv2 and is available on Armada SoCs.
|
||||
*
|
||||
* The main visible difference is that NFCv1 only has Hamming ECC
|
||||
* capabilities, while NFCv2 also embeds a BCH ECC engine. Also, DMA
|
||||
* is not used with NFCv2.
|
||||
*
|
||||
* The ECC layouts are depicted in details in Marvell AN-379, but here
|
||||
* is a brief description.
|
||||
*
|
||||
* When using Hamming, the data is split in 512B chunks (either 1, 2
|
||||
* or 4) and each chunk will have its own ECC "digest" of 6B at the
|
||||
* beginning of the OOB area and eventually the remaining free OOB
|
||||
* bytes (also called "spare" bytes in the driver). This engine
|
||||
* corrects up to 1 bit per chunk and detects reliably an error if
|
||||
* there are at most 2 bitflips. Here is the page layout used by the
|
||||
* controller when Hamming is chosen:
|
||||
*
|
||||
* +-------------------------------------------------------------+
|
||||
* | Data 1 | ... | Data N | ECC 1 | ... | ECCN | Free OOB bytes |
|
||||
* +-------------------------------------------------------------+
|
||||
*
|
||||
* When using the BCH engine, there are N identical (data + free OOB +
|
||||
* ECC) sections and potentially an extra one to deal with
|
||||
* configurations where the chosen (data + free OOB + ECC) sizes do
|
||||
* not align with the page (data + OOB) size. ECC bytes are always
|
||||
* 30B per ECC chunk. Here is the page layout used by the controller
|
||||
* when BCH is chosen:
|
||||
*
|
||||
* +-----------------------------------------
|
||||
* | Data 1 | Free OOB bytes 1 | ECC 1 | ...
|
||||
* +-----------------------------------------
|
||||
*
|
||||
* -------------------------------------------
|
||||
* ... | Data N | Free OOB bytes N | ECC N |
|
||||
* -------------------------------------------
|
||||
*
|
||||
* --------------------------------------------+
|
||||
* Last Data | Last Free OOB bytes | Last ECC |
|
||||
* --------------------------------------------+
|
||||
*
|
||||
* In both cases, the layout seen by the user is always: all data
|
||||
* first, then all free OOB bytes and finally all ECC bytes. With BCH,
|
||||
* ECC bytes are 30B long and are padded with 0xFF to align on 32
|
||||
* bytes.
|
||||
*
|
||||
* The controller has certain limitations that are handled by the
|
||||
* driver:
|
||||
* - It can only read 2k at a time. To overcome this limitation, the
|
||||
* driver issues data cycles on the bus, without issuing new
|
||||
* CMD + ADDR cycles. The Marvell term is "naked" operations.
|
||||
* - The ECC strength in BCH mode cannot be tuned. It is fixed 16
|
||||
* bits. What can be tuned is the ECC block size as long as it
|
||||
* stays between 512B and 2kiB. It's usually chosen based on the
|
||||
* chip ECC requirements. For instance, using 2kiB ECC chunks
|
||||
* provides 4b/512B correctability.
|
||||
* - The controller will always treat data bytes, free OOB bytes
|
||||
* and ECC bytes in that order, no matter what the real layout is
|
||||
* (which is usually all data then all OOB bytes). The
|
||||
* marvell_nfc_layouts array below contains the currently
|
||||
* supported layouts.
|
||||
* - Because of these weird layouts, the Bad Block Markers can be
|
||||
* located in data section. In this case, the NAND_BBT_NO_OOB_BBM
|
||||
* option must be set to prevent scanning/writing bad block
|
||||
* markers.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -217,8 +284,11 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
|
|||
MARVELL_LAYOUT( 512, 512, 1, 1, 1, 512, 8, 8, 0, 0, 0),
|
||||
MARVELL_LAYOUT( 2048, 512, 1, 1, 1, 2048, 40, 24, 0, 0, 0),
|
||||
MARVELL_LAYOUT( 2048, 512, 4, 1, 1, 2048, 32, 30, 0, 0, 0),
|
||||
MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,32, 30),
|
||||
MARVELL_LAYOUT( 4096, 512, 4, 2, 2, 2048, 32, 30, 0, 0, 0),
|
||||
MARVELL_LAYOUT( 4096, 512, 8, 5, 4, 1024, 0, 30, 0, 64, 30),
|
||||
MARVELL_LAYOUT( 8192, 512, 4, 4, 4, 2048, 0, 30, 0, 0, 0),
|
||||
MARVELL_LAYOUT( 8192, 512, 8, 9, 8, 1024, 0, 30, 0, 160, 30),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -634,9 +704,8 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void marvell_nfc_select_chip(struct mtd_info *mtd, int die_nr)
|
||||
static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
|
||||
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
|
||||
u32 ndcr_generic;
|
||||
|
@ -686,7 +755,7 @@ static irqreturn_t marvell_nfc_isr(int irq, void *dev_id)
|
|||
|
||||
marvell_nfc_disable_int(nfc, st & NDCR_ALL_INT);
|
||||
|
||||
if (!(st & (NDSR_RDDREQ | NDSR_WRDREQ | NDSR_WRCMDREQ)))
|
||||
if (st & (NDSR_RDY(0) | NDSR_RDY(1)))
|
||||
complete(&nfc->complete);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -959,18 +1028,15 @@ static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u8 *buf,
|
||||
static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct nand_chip *chip, u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi,
|
||||
true, page);
|
||||
}
|
||||
|
||||
static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
u8 *buf, int oob_required,
|
||||
int page)
|
||||
static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
|
||||
unsigned int full_sz = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
|
||||
|
@ -1008,8 +1074,7 @@ static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
|
|||
* it appears before the ECC bytes when reading), the ->read_oob_raw() function
|
||||
* also stands for ->read_oob().
|
||||
*/
|
||||
static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, int page)
|
||||
static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page)
|
||||
{
|
||||
/* Invalidate page cache */
|
||||
chip->pagebuf = -1;
|
||||
|
@ -1073,8 +1138,7 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip,
|
||||
const u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
|
@ -1082,8 +1146,7 @@ static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
|
|||
true, page);
|
||||
}
|
||||
|
||||
static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int marvell_nfc_hw_ecc_hmg_write_page(struct nand_chip *chip,
|
||||
const u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
|
@ -1102,10 +1165,11 @@ static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
|
|||
* it appears before the ECC bytes when reading), the ->write_oob_raw() function
|
||||
* also stands for ->write_oob().
|
||||
*/
|
||||
static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip,
|
||||
int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
/* Invalidate page cache */
|
||||
chip->pagebuf = -1;
|
||||
|
||||
|
@ -1116,10 +1180,10 @@ static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
|
|||
}
|
||||
|
||||
/* BCH read helpers */
|
||||
static int marvell_nfc_hw_ecc_bch_read_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u8 *buf,
|
||||
static int marvell_nfc_hw_ecc_bch_read_page_raw(struct nand_chip *chip, u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
|
||||
u8 *oob = chip->oob_poi;
|
||||
int chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
|
||||
|
@ -1228,17 +1292,17 @@ static void marvell_nfc_hw_ecc_bch_read_chunk(struct nand_chip *chip, int chunk,
|
|||
}
|
||||
}
|
||||
|
||||
static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip,
|
||||
u8 *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
|
||||
int data_len = lt->data_bytes, spare_len = lt->spare_bytes, ecc_len;
|
||||
u8 *data = buf, *spare = chip->oob_poi, *ecc;
|
||||
int data_len = lt->data_bytes, spare_len = lt->spare_bytes;
|
||||
u8 *data = buf, *spare = chip->oob_poi;
|
||||
int max_bitflips = 0;
|
||||
u32 failure_mask = 0;
|
||||
int chunk, ecc_offset_in_page, ret;
|
||||
int chunk, ret;
|
||||
|
||||
/*
|
||||
* With BCH, OOB is not fully used (and thus not read entirely), not
|
||||
|
@ -1279,73 +1343,98 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
|
|||
* the controller in normal mode and must be re-read in raw mode. To
|
||||
* avoid dropping the performances, we prefer not to include them. The
|
||||
* user should re-read the page in raw mode if ECC bytes are required.
|
||||
*/
|
||||
|
||||
/*
|
||||
* In case there is any subpage read error reported by ->correct(), we
|
||||
* usually re-read only ECC bytes in raw mode and check if the whole
|
||||
* page is empty. In this case, it is normal that the ECC check failed
|
||||
* and we just ignore the error.
|
||||
*
|
||||
* However, for any subpage read error reported by ->correct(), the ECC
|
||||
* bytes must be read in raw mode and the full subpage must be checked
|
||||
* to see if it is entirely empty of if there was an actual error.
|
||||
* However, it has been empirically observed that for some layouts (e.g
|
||||
* 2k page, 8b strength per 512B chunk), the controller tries to correct
|
||||
* bits and may create itself bitflips in the erased area. To overcome
|
||||
* this strange behavior, the whole page is re-read in raw mode, not
|
||||
* only the ECC bytes.
|
||||
*/
|
||||
for (chunk = 0; chunk < lt->nchunks; chunk++) {
|
||||
int data_off_in_page, spare_off_in_page, ecc_off_in_page;
|
||||
int data_off, spare_off, ecc_off;
|
||||
int data_len, spare_len, ecc_len;
|
||||
|
||||
/* No failure reported for this chunk, move to the next one */
|
||||
if (!(failure_mask & BIT(chunk)))
|
||||
continue;
|
||||
|
||||
/* Derive ECC bytes positions (in page/buffer) and length */
|
||||
ecc = chip->oob_poi +
|
||||
(lt->full_chunk_cnt * lt->spare_bytes) +
|
||||
data_off_in_page = chunk * (lt->data_bytes + lt->spare_bytes +
|
||||
lt->ecc_bytes);
|
||||
spare_off_in_page = data_off_in_page +
|
||||
(chunk < lt->full_chunk_cnt ? lt->data_bytes :
|
||||
lt->last_data_bytes);
|
||||
ecc_off_in_page = spare_off_in_page +
|
||||
(chunk < lt->full_chunk_cnt ? lt->spare_bytes :
|
||||
lt->last_spare_bytes);
|
||||
|
||||
data_off = chunk * lt->data_bytes;
|
||||
spare_off = chunk * lt->spare_bytes;
|
||||
ecc_off = (lt->full_chunk_cnt * lt->spare_bytes) +
|
||||
lt->last_spare_bytes +
|
||||
(chunk * ALIGN(lt->ecc_bytes, 32));
|
||||
ecc_offset_in_page =
|
||||
(chunk * (lt->data_bytes + lt->spare_bytes +
|
||||
lt->ecc_bytes)) +
|
||||
(chunk < lt->full_chunk_cnt ?
|
||||
lt->data_bytes + lt->spare_bytes :
|
||||
lt->last_data_bytes + lt->last_spare_bytes);
|
||||
ecc_len = chunk < lt->full_chunk_cnt ?
|
||||
lt->ecc_bytes : lt->last_ecc_bytes;
|
||||
(chunk * (lt->ecc_bytes + 2));
|
||||
|
||||
/* Do the actual raw read of the ECC bytes */
|
||||
nand_change_read_column_op(chip, ecc_offset_in_page,
|
||||
ecc, ecc_len, false);
|
||||
data_len = chunk < lt->full_chunk_cnt ? lt->data_bytes :
|
||||
lt->last_data_bytes;
|
||||
spare_len = chunk < lt->full_chunk_cnt ? lt->spare_bytes :
|
||||
lt->last_spare_bytes;
|
||||
ecc_len = chunk < lt->full_chunk_cnt ? lt->ecc_bytes :
|
||||
lt->last_ecc_bytes;
|
||||
|
||||
/* Derive data/spare bytes positions (in buffer) and length */
|
||||
data = buf + (chunk * lt->data_bytes);
|
||||
data_len = chunk < lt->full_chunk_cnt ?
|
||||
lt->data_bytes : lt->last_data_bytes;
|
||||
spare = chip->oob_poi + (chunk * (lt->spare_bytes +
|
||||
lt->ecc_bytes));
|
||||
spare_len = chunk < lt->full_chunk_cnt ?
|
||||
lt->spare_bytes : lt->last_spare_bytes;
|
||||
/*
|
||||
* Only re-read the ECC bytes, unless we are using the 2k/8b
|
||||
* layout which is buggy in the sense that the ECC engine will
|
||||
* try to correct data bytes anyway, creating bitflips. In this
|
||||
* case, re-read the entire page.
|
||||
*/
|
||||
if (lt->writesize == 2048 && lt->strength == 8) {
|
||||
nand_change_read_column_op(chip, data_off_in_page,
|
||||
buf + data_off, data_len,
|
||||
false);
|
||||
nand_change_read_column_op(chip, spare_off_in_page,
|
||||
chip->oob_poi + spare_off, spare_len,
|
||||
false);
|
||||
}
|
||||
|
||||
nand_change_read_column_op(chip, ecc_off_in_page,
|
||||
chip->oob_poi + ecc_off, ecc_len,
|
||||
false);
|
||||
|
||||
/* Check the entire chunk (data + spare + ecc) for emptyness */
|
||||
marvell_nfc_check_empty_chunk(chip, data, data_len, spare,
|
||||
spare_len, ecc, ecc_len,
|
||||
marvell_nfc_check_empty_chunk(chip, buf + data_off, data_len,
|
||||
chip->oob_poi + spare_off, spare_len,
|
||||
chip->oob_poi + ecc_off, ecc_len,
|
||||
&max_bitflips);
|
||||
}
|
||||
|
||||
return max_bitflips;
|
||||
}
|
||||
|
||||
static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, int page)
|
||||
static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct nand_chip *chip, int page)
|
||||
{
|
||||
/* Invalidate page cache */
|
||||
chip->pagebuf = -1;
|
||||
|
||||
return chip->ecc.read_page_raw(mtd, chip, chip->data_buf, true, page);
|
||||
return chip->ecc.read_page_raw(chip, chip->data_buf, true, page);
|
||||
}
|
||||
|
||||
static int marvell_nfc_hw_ecc_bch_read_oob(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, int page)
|
||||
static int marvell_nfc_hw_ecc_bch_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
/* Invalidate page cache */
|
||||
chip->pagebuf = -1;
|
||||
|
||||
return chip->ecc.read_page(mtd, chip, chip->data_buf, true, page);
|
||||
return chip->ecc.read_page(chip, chip->data_buf, true, page);
|
||||
}
|
||||
|
||||
/* BCH write helpers */
|
||||
static int marvell_nfc_hw_ecc_bch_write_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int marvell_nfc_hw_ecc_bch_write_page_raw(struct nand_chip *chip,
|
||||
const u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
|
@ -1458,11 +1547,11 @@ marvell_nfc_hw_ecc_bch_write_chunk(struct nand_chip *chip, int chunk,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
|
||||
const u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
|
||||
const u8 *data = buf;
|
||||
const u8 *spare = chip->oob_poi;
|
||||
|
@ -1507,27 +1596,29 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct nand_chip *chip,
|
||||
int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
/* Invalidate page cache */
|
||||
chip->pagebuf = -1;
|
||||
|
||||
memset(chip->data_buf, 0xFF, mtd->writesize);
|
||||
|
||||
return chip->ecc.write_page_raw(mtd, chip, chip->data_buf, true, page);
|
||||
return chip->ecc.write_page_raw(chip, chip->data_buf, true, page);
|
||||
}
|
||||
|
||||
static int marvell_nfc_hw_ecc_bch_write_oob(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, int page)
|
||||
static int marvell_nfc_hw_ecc_bch_write_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
/* Invalidate page cache */
|
||||
chip->pagebuf = -1;
|
||||
|
||||
memset(chip->data_buf, 0xFF, mtd->writesize);
|
||||
|
||||
return chip->ecc.write_page(mtd, chip, chip->data_buf, true, page);
|
||||
return chip->ecc.write_page(chip, chip->data_buf, true, page);
|
||||
}
|
||||
|
||||
/* NAND framework ->exec_op() hooks and related helpers */
|
||||
|
@ -2097,6 +2188,16 @@ static int marvell_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
/* Special care for the layout 2k/8-bit/512B */
|
||||
if (l->writesize == 2048 && l->strength == 8) {
|
||||
if (mtd->oobsize < 128) {
|
||||
dev_err(nfc->dev, "Requested layout needs at least 128 OOB bytes\n");
|
||||
return -ENOTSUPP;
|
||||
} else {
|
||||
chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
|
||||
}
|
||||
}
|
||||
|
||||
mtd_set_ooblayout(mtd, &marvell_nand_ooblayout_ops);
|
||||
ecc->steps = l->nchunks;
|
||||
ecc->size = l->data_bytes;
|
||||
|
@ -2192,11 +2293,10 @@ static struct nand_bbt_descr bbt_mirror_descr = {
|
|||
.pattern = bbt_mirror_pattern
|
||||
};
|
||||
|
||||
static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
|
||||
static int marvell_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
|
||||
const struct nand_data_interface
|
||||
*conf)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
|
||||
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
|
||||
unsigned int period_ns = 1000000000 / clk_get_rate(nfc->core_clk) * 2;
|
||||
|
@ -2540,7 +2640,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
|
|||
|
||||
chip->options |= NAND_BUSWIDTH_AUTO;
|
||||
|
||||
ret = nand_scan(mtd, marvell_nand->nsels);
|
||||
ret = nand_scan(chip, marvell_nand->nsels);
|
||||
if (ret) {
|
||||
dev_err(dev, "could not scan the nand chip\n");
|
||||
return ret;
|
||||
|
@ -2553,7 +2653,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
|
|||
ret = mtd_device_register(mtd, NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register mtd device: %d\n", ret);
|
||||
nand_release(mtd);
|
||||
nand_release(chip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2608,7 +2708,7 @@ static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
|
|||
struct marvell_nand_chip *entry, *temp;
|
||||
|
||||
list_for_each_entry_safe(entry, temp, &nfc->chips, node) {
|
||||
nand_release(nand_to_mtd(&entry->chip));
|
||||
nand_release(&entry->chip);
|
||||
list_del(&entry->node);
|
||||
}
|
||||
}
|
||||
|
@ -2699,24 +2799,23 @@ static int marvell_nfc_init(struct marvell_nfc *nfc)
|
|||
struct regmap *sysctrl_base =
|
||||
syscon_regmap_lookup_by_phandle(np,
|
||||
"marvell,system-controller");
|
||||
u32 reg;
|
||||
|
||||
if (IS_ERR(sysctrl_base))
|
||||
return PTR_ERR(sysctrl_base);
|
||||
|
||||
reg = GENCONF_SOC_DEVICE_MUX_NFC_EN |
|
||||
regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX,
|
||||
GENCONF_SOC_DEVICE_MUX_NFC_EN |
|
||||
GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
|
||||
GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
|
||||
GENCONF_SOC_DEVICE_MUX_NFC_INT_EN;
|
||||
regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
|
||||
GENCONF_SOC_DEVICE_MUX_NFC_INT_EN);
|
||||
|
||||
regmap_read(sysctrl_base, GENCONF_CLK_GATING_CTRL, ®);
|
||||
reg |= GENCONF_CLK_GATING_CTRL_ND_GATE;
|
||||
regmap_write(sysctrl_base, GENCONF_CLK_GATING_CTRL, reg);
|
||||
regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL,
|
||||
GENCONF_CLK_GATING_CTRL_ND_GATE,
|
||||
GENCONF_CLK_GATING_CTRL_ND_GATE);
|
||||
|
||||
regmap_read(sysctrl_base, GENCONF_ND_CLK_CTRL, ®);
|
||||
reg |= GENCONF_ND_CLK_CTRL_EN;
|
||||
regmap_write(sysctrl_base, GENCONF_ND_CLK_CTRL, reg);
|
||||
regmap_update_bits(sysctrl_base, GENCONF_ND_CLK_CTRL,
|
||||
GENCONF_ND_CLK_CTRL_EN,
|
||||
GENCONF_ND_CLK_CTRL_EN);
|
||||
}
|
||||
|
||||
/* Configure the DMA if appropriate */
|
||||
|
|
|
@ -263,8 +263,10 @@ static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
|
|||
}
|
||||
|
||||
/* Control chip select signals */
|
||||
static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void mpc5121_nfc_select_chip(struct nand_chip *nand, int chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(nand);
|
||||
|
||||
if (chip < 0) {
|
||||
nfc_clear(mtd, NFC_CONFIG1, NFC_CE);
|
||||
return;
|
||||
|
@ -299,9 +301,9 @@ static int ads5121_chipselect_init(struct mtd_info *mtd)
|
|||
}
|
||||
|
||||
/* Control chips select signal on ADS5121 board */
|
||||
static void ads5121_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void ads5121_select_chip(struct nand_chip *nand, int chip)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(nand);
|
||||
struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
|
||||
u8 v;
|
||||
|
||||
|
@ -309,16 +311,16 @@ static void ads5121_select_chip(struct mtd_info *mtd, int chip)
|
|||
v |= 0x0F;
|
||||
|
||||
if (chip >= 0) {
|
||||
mpc5121_nfc_select_chip(mtd, 0);
|
||||
mpc5121_nfc_select_chip(nand, 0);
|
||||
v &= ~(1 << chip);
|
||||
} else
|
||||
mpc5121_nfc_select_chip(mtd, -1);
|
||||
mpc5121_nfc_select_chip(nand, -1);
|
||||
|
||||
out_8(prv->csreg, v);
|
||||
}
|
||||
|
||||
/* Read NAND Ready/Busy signal */
|
||||
static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
|
||||
static int mpc5121_nfc_dev_ready(struct nand_chip *nand)
|
||||
{
|
||||
/*
|
||||
* NFC handles ready/busy signal internally. Therefore, this function
|
||||
|
@ -328,10 +330,10 @@ static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
|
|||
}
|
||||
|
||||
/* Write command to NAND flash */
|
||||
static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
|
||||
static void mpc5121_nfc_command(struct nand_chip *chip, unsigned command,
|
||||
int column, int page)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
|
||||
|
||||
prv->column = (column >= 0) ? column : 0;
|
||||
|
@ -362,7 +364,7 @@ static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
|
|||
break;
|
||||
|
||||
case NAND_CMD_SEQIN:
|
||||
mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page);
|
||||
mpc5121_nfc_command(chip, NAND_CMD_READ0, column, page);
|
||||
column = 0;
|
||||
break;
|
||||
|
||||
|
@ -493,34 +495,24 @@ static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len,
|
|||
}
|
||||
|
||||
/* Read data from NFC buffers */
|
||||
static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void mpc5121_nfc_read_buf(struct nand_chip *chip, u_char *buf, int len)
|
||||
{
|
||||
mpc5121_nfc_buf_copy(mtd, buf, len, 0);
|
||||
mpc5121_nfc_buf_copy(nand_to_mtd(chip), buf, len, 0);
|
||||
}
|
||||
|
||||
/* Write data to NFC buffers */
|
||||
static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
|
||||
const u_char *buf, int len)
|
||||
static void mpc5121_nfc_write_buf(struct nand_chip *chip, const u_char *buf,
|
||||
int len)
|
||||
{
|
||||
mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
|
||||
mpc5121_nfc_buf_copy(nand_to_mtd(chip), (u_char *)buf, len, 1);
|
||||
}
|
||||
|
||||
/* Read byte from NFC buffers */
|
||||
static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
|
||||
static u8 mpc5121_nfc_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
u8 tmp;
|
||||
|
||||
mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp));
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* Read word from NFC buffers */
|
||||
static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
|
||||
{
|
||||
u16 tmp;
|
||||
|
||||
mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
|
||||
mpc5121_nfc_read_buf(chip, &tmp, sizeof(tmp));
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
@ -700,15 +692,14 @@ static int mpc5121_nfc_probe(struct platform_device *op)
|
|||
}
|
||||
|
||||
mtd->name = "MPC5121 NAND";
|
||||
chip->dev_ready = mpc5121_nfc_dev_ready;
|
||||
chip->cmdfunc = mpc5121_nfc_command;
|
||||
chip->read_byte = mpc5121_nfc_read_byte;
|
||||
chip->read_word = mpc5121_nfc_read_word;
|
||||
chip->read_buf = mpc5121_nfc_read_buf;
|
||||
chip->write_buf = mpc5121_nfc_write_buf;
|
||||
chip->legacy.dev_ready = mpc5121_nfc_dev_ready;
|
||||
chip->legacy.cmdfunc = mpc5121_nfc_command;
|
||||
chip->legacy.read_byte = mpc5121_nfc_read_byte;
|
||||
chip->legacy.read_buf = mpc5121_nfc_read_buf;
|
||||
chip->legacy.write_buf = mpc5121_nfc_write_buf;
|
||||
chip->select_chip = mpc5121_nfc_select_chip;
|
||||
chip->set_features = nand_get_set_features_notsupp;
|
||||
chip->get_features = nand_get_set_features_notsupp;
|
||||
chip->legacy.set_features = nand_get_set_features_notsupp;
|
||||
chip->legacy.get_features = nand_get_set_features_notsupp;
|
||||
chip->bbt_options = NAND_BBT_USE_FLASH;
|
||||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
chip->ecc.algo = NAND_ECC_HAMMING;
|
||||
|
@ -778,7 +769,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
|
|||
}
|
||||
|
||||
/* Detect NAND chips */
|
||||
retval = nand_scan(mtd, be32_to_cpup(chips_no));
|
||||
retval = nand_scan(chip, be32_to_cpup(chips_no));
|
||||
if (retval) {
|
||||
dev_err(dev, "NAND Flash not found !\n");
|
||||
goto error;
|
||||
|
@ -828,7 +819,7 @@ static int mpc5121_nfc_remove(struct platform_device *op)
|
|||
struct device *dev = &op->dev;
|
||||
struct mtd_info *mtd = dev_get_drvdata(dev);
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(mtd_to_nand(mtd));
|
||||
mpc5121_nfc_free(dev, mtd);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -389,23 +389,22 @@ static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void mtk_nfc_select_chip(struct nand_chip *nand, int chip)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(nand);
|
||||
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
|
||||
|
||||
if (chip < 0)
|
||||
return;
|
||||
|
||||
mtk_nfc_hw_runtime_config(mtd);
|
||||
mtk_nfc_hw_runtime_config(nand_to_mtd(nand));
|
||||
|
||||
nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
|
||||
}
|
||||
|
||||
static int mtk_nfc_dev_ready(struct mtd_info *mtd)
|
||||
static int mtk_nfc_dev_ready(struct nand_chip *nand)
|
||||
{
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(nand);
|
||||
|
||||
if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
|
||||
return 0;
|
||||
|
@ -413,9 +412,10 @@ static int mtk_nfc_dev_ready(struct mtd_info *mtd)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
|
||||
static void mtk_nfc_cmd_ctrl(struct nand_chip *chip, int dat,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(chip);
|
||||
|
||||
if (ctrl & NAND_ALE) {
|
||||
mtk_nfc_send_address(nfc, dat);
|
||||
|
@ -438,9 +438,8 @@ static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
|
|||
dev_err(nfc->dev, "data not ready\n");
|
||||
}
|
||||
|
||||
static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
|
||||
static inline u8 mtk_nfc_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(chip);
|
||||
u32 reg;
|
||||
|
||||
|
@ -467,17 +466,17 @@ static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
|
|||
return nfi_readb(nfc, NFI_DATAR);
|
||||
}
|
||||
|
||||
static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
||||
static void mtk_nfc_read_buf(struct nand_chip *chip, u8 *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = mtk_nfc_read_byte(mtd);
|
||||
buf[i] = mtk_nfc_read_byte(chip);
|
||||
}
|
||||
|
||||
static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
|
||||
static void mtk_nfc_write_byte(struct nand_chip *chip, u8 byte)
|
||||
{
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(chip);
|
||||
u32 reg;
|
||||
|
||||
reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
|
||||
|
@ -496,18 +495,18 @@ static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
|
|||
nfi_writeb(nfc, byte, NFI_DATAW);
|
||||
}
|
||||
|
||||
static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
||||
static void mtk_nfc_write_buf(struct nand_chip *chip, const u8 *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
mtk_nfc_write_byte(mtd, buf[i]);
|
||||
mtk_nfc_write_byte(chip, buf[i]);
|
||||
}
|
||||
|
||||
static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
|
||||
static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline,
|
||||
const struct nand_data_interface *conf)
|
||||
{
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(chip);
|
||||
const struct nand_sdr_timings *timings;
|
||||
u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
|
||||
|
||||
|
@ -807,27 +806,27 @@ static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const u8 *buf,
|
||||
static int mtk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf,
|
||||
int oob_on, int page)
|
||||
{
|
||||
return mtk_nfc_write_page(mtd, chip, buf, page, 0);
|
||||
return mtk_nfc_write_page(nand_to_mtd(chip), chip, buf, page, 0);
|
||||
}
|
||||
|
||||
static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const u8 *buf, int oob_on, int pg)
|
||||
static int mtk_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf,
|
||||
int oob_on, int pg)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(chip);
|
||||
|
||||
mtk_nfc_format_page(mtd, buf);
|
||||
return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1);
|
||||
}
|
||||
|
||||
static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u32 offset,
|
||||
static int mtk_nfc_write_subpage_hwecc(struct nand_chip *chip, u32 offset,
|
||||
u32 data_len, const u8 *buf,
|
||||
int oob_on, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(chip);
|
||||
int ret;
|
||||
|
||||
|
@ -839,10 +838,9 @@ static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
|
|||
return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1);
|
||||
}
|
||||
|
||||
static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int mtk_nfc_write_oob_std(struct nand_chip *chip, int page)
|
||||
{
|
||||
return mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
|
||||
return mtk_nfc_write_page_raw(chip, NULL, 1, page);
|
||||
}
|
||||
|
||||
static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
|
||||
|
@ -969,23 +967,25 @@ done:
|
|||
return bitflips;
|
||||
}
|
||||
|
||||
static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u32 off,
|
||||
static int mtk_nfc_read_subpage_hwecc(struct nand_chip *chip, u32 off,
|
||||
u32 len, u8 *p, int pg)
|
||||
{
|
||||
return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0);
|
||||
return mtk_nfc_read_subpage(nand_to_mtd(chip), chip, off, len, p, pg,
|
||||
0);
|
||||
}
|
||||
|
||||
static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u8 *p,
|
||||
int oob_on, int pg)
|
||||
static int mtk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *p, int oob_on,
|
||||
int pg)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0);
|
||||
}
|
||||
|
||||
static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
u8 *buf, int oob_on, int page)
|
||||
static int mtk_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_on,
|
||||
int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
|
||||
struct mtk_nfc *nfc = nand_get_controller_data(chip);
|
||||
struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
|
||||
|
@ -1011,10 +1011,9 @@ static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int mtk_nfc_read_oob_std(struct nand_chip *chip, int page)
|
||||
{
|
||||
return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
|
||||
return mtk_nfc_read_page_raw(chip, NULL, 1, page);
|
||||
}
|
||||
|
||||
static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
|
||||
|
@ -1333,13 +1332,13 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
|
|||
nand_set_controller_data(nand, nfc);
|
||||
|
||||
nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
|
||||
nand->dev_ready = mtk_nfc_dev_ready;
|
||||
nand->legacy.dev_ready = mtk_nfc_dev_ready;
|
||||
nand->select_chip = mtk_nfc_select_chip;
|
||||
nand->write_byte = mtk_nfc_write_byte;
|
||||
nand->write_buf = mtk_nfc_write_buf;
|
||||
nand->read_byte = mtk_nfc_read_byte;
|
||||
nand->read_buf = mtk_nfc_read_buf;
|
||||
nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
|
||||
nand->legacy.write_byte = mtk_nfc_write_byte;
|
||||
nand->legacy.write_buf = mtk_nfc_write_buf;
|
||||
nand->legacy.read_byte = mtk_nfc_read_byte;
|
||||
nand->legacy.read_buf = mtk_nfc_read_buf;
|
||||
nand->legacy.cmd_ctrl = mtk_nfc_cmd_ctrl;
|
||||
nand->setup_data_interface = mtk_nfc_setup_data_interface;
|
||||
|
||||
/* set default mode in case dt entry is missing */
|
||||
|
@ -1365,14 +1364,14 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
|
|||
|
||||
mtk_nfc_hw_init(nfc);
|
||||
|
||||
ret = nand_scan(mtd, nsels);
|
||||
ret = nand_scan(nand, nsels);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mtd_device_register(mtd, NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "mtd parse partition error\n");
|
||||
nand_release(mtd);
|
||||
nand_release(nand);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1538,7 +1537,7 @@ static int mtk_nfc_remove(struct platform_device *pdev)
|
|||
while (!list_empty(&nfc->chips)) {
|
||||
chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
|
||||
node);
|
||||
nand_release(nand_to_mtd(&chip->nand));
|
||||
nand_release(&chip->nand);
|
||||
list_del(&chip->node);
|
||||
}
|
||||
|
||||
|
|
|
@ -136,8 +136,8 @@ struct mxc_nand_devtype_data {
|
|||
void (*irq_control)(struct mxc_nand_host *, int);
|
||||
u32 (*get_ecc_status)(struct mxc_nand_host *);
|
||||
const struct mtd_ooblayout_ops *ooblayout;
|
||||
void (*select_chip)(struct mtd_info *mtd, int chip);
|
||||
int (*setup_data_interface)(struct mtd_info *mtd, int csline,
|
||||
void (*select_chip)(struct nand_chip *chip, int cs);
|
||||
int (*setup_data_interface)(struct nand_chip *chip, int csline,
|
||||
const struct nand_data_interface *conf);
|
||||
void (*enable_hwecc)(struct nand_chip *chip, bool enable);
|
||||
|
||||
|
@ -701,7 +701,7 @@ static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable)
|
|||
}
|
||||
|
||||
/* This functions is used by upper layer to checks if device is ready */
|
||||
static int mxc_nand_dev_ready(struct mtd_info *mtd)
|
||||
static int mxc_nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
/*
|
||||
* NFC handles R/B internally. Therefore, this function
|
||||
|
@ -816,8 +816,8 @@ static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf,
|
|||
return max_bitflips;
|
||||
}
|
||||
|
||||
static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int mxc_nand_read_page(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
void *oob_buf;
|
||||
|
@ -830,8 +830,8 @@ static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return host->devtype_data->read_page(chip, buf, oob_buf, 1, page);
|
||||
}
|
||||
|
||||
static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int mxc_nand_read_page_raw(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
void *oob_buf;
|
||||
|
@ -844,8 +844,7 @@ static int mxc_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return host->devtype_data->read_page(chip, buf, oob_buf, 0, page);
|
||||
}
|
||||
|
||||
static int mxc_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int mxc_nand_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
|
||||
|
@ -874,22 +873,21 @@ static int mxc_nand_write_page(struct nand_chip *chip, const uint8_t *buf,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mxc_nand_write_page_ecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
static int mxc_nand_write_page_ecc(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
return mxc_nand_write_page(chip, buf, true, page);
|
||||
}
|
||||
|
||||
static int mxc_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
static int mxc_nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
return mxc_nand_write_page(chip, buf, false, page);
|
||||
}
|
||||
|
||||
static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int mxc_nand_write_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
|
||||
memset(host->data_buf, 0xff, mtd->writesize);
|
||||
|
@ -897,9 +895,8 @@ static int mxc_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return mxc_nand_write_page(chip, host->data_buf, false, page);
|
||||
}
|
||||
|
||||
static u_char mxc_nand_read_byte(struct mtd_info *mtd)
|
||||
static u_char mxc_nand_read_byte(struct nand_chip *nand_chip)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
uint8_t ret;
|
||||
|
||||
|
@ -921,25 +918,13 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
uint16_t ret;
|
||||
|
||||
ret = *(uint16_t *)(host->data_buf + host->buf_start);
|
||||
host->buf_start += 2;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Write data of length len to buffer buf. The data to be
|
||||
* written on NAND Flash is first copied to RAMbuffer. After the Data Input
|
||||
* Operation by the NFC, the data is written to NAND Flash */
|
||||
static void mxc_nand_write_buf(struct mtd_info *mtd,
|
||||
const u_char *buf, int len)
|
||||
static void mxc_nand_write_buf(struct nand_chip *nand_chip, const u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(nand_chip);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
u16 col = host->buf_start;
|
||||
int n = mtd->oobsize + mtd->writesize - col;
|
||||
|
@ -955,9 +940,10 @@ static void mxc_nand_write_buf(struct mtd_info *mtd,
|
|||
* Flash first the data output cycle is initiated by the NFC, which copies
|
||||
* the data to RAMbuffer. This data of length len is then copied to buffer buf.
|
||||
*/
|
||||
static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void mxc_nand_read_buf(struct nand_chip *nand_chip, u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(nand_chip);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
u16 col = host->buf_start;
|
||||
int n = mtd->oobsize + mtd->writesize - col;
|
||||
|
@ -971,9 +957,8 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
|||
|
||||
/* This function is used by upper layer for select and
|
||||
* deselect of the NAND chip */
|
||||
static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
|
||||
static void mxc_nand_select_chip_v1_v3(struct nand_chip *nand_chip, int chip)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
|
||||
if (chip == -1) {
|
||||
|
@ -992,9 +977,8 @@ static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip)
|
|||
}
|
||||
}
|
||||
|
||||
static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
|
||||
static void mxc_nand_select_chip_v2(struct nand_chip *nand_chip, int chip)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
|
||||
if (chip == -1) {
|
||||
|
@ -1155,11 +1139,10 @@ static void preset_v1(struct mtd_info *mtd)
|
|||
writew(0x4, NFC_V1_V2_WRPROT);
|
||||
}
|
||||
|
||||
static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd, int csline,
|
||||
static int mxc_nand_v2_setup_data_interface(struct nand_chip *chip, int csline,
|
||||
const struct nand_data_interface *conf)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
int tRC_min_ns, tRC_ps, ret;
|
||||
unsigned long rate, rate_round;
|
||||
const struct nand_sdr_timings *timings;
|
||||
|
@ -1349,10 +1332,10 @@ static void preset_v3(struct mtd_info *mtd)
|
|||
|
||||
/* Used by the upper layer to write command to NAND Flash for
|
||||
* different operations to be carried out on NAND Flash */
|
||||
static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
|
||||
static void mxc_nand_command(struct nand_chip *nand_chip, unsigned command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(nand_chip);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
|
||||
dev_dbg(host->dev, "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
|
||||
|
@ -1409,17 +1392,17 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
|
|||
}
|
||||
}
|
||||
|
||||
static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int addr, u8 *subfeature_param)
|
||||
static int mxc_nand_set_features(struct nand_chip *chip, int addr,
|
||||
u8 *subfeature_param)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
int i;
|
||||
|
||||
host->buf_start = 0;
|
||||
|
||||
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
|
||||
chip->write_byte(mtd, subfeature_param[i]);
|
||||
chip->legacy.write_byte(chip, subfeature_param[i]);
|
||||
|
||||
memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
|
||||
host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
|
||||
|
@ -1429,11 +1412,11 @@ static int mxc_nand_set_features(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int addr, u8 *subfeature_param)
|
||||
static int mxc_nand_get_features(struct nand_chip *chip, int addr,
|
||||
u8 *subfeature_param)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct mxc_nand_host *host = nand_get_controller_data(chip);
|
||||
int i;
|
||||
|
||||
host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
|
||||
|
@ -1443,7 +1426,7 @@ static int mxc_nand_get_features(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
host->buf_start = 0;
|
||||
|
||||
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
|
||||
*subfeature_param++ = chip->read_byte(mtd);
|
||||
*subfeature_param++ = chip->legacy.read_byte(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1786,18 +1769,17 @@ static int mxcnd_probe(struct platform_device *pdev)
|
|||
mtd->name = DRIVER_NAME;
|
||||
|
||||
/* 50 us command delay time */
|
||||
this->chip_delay = 5;
|
||||
this->legacy.chip_delay = 5;
|
||||
|
||||
nand_set_controller_data(this, host);
|
||||
nand_set_flash_node(this, pdev->dev.of_node),
|
||||
this->dev_ready = mxc_nand_dev_ready;
|
||||
this->cmdfunc = mxc_nand_command;
|
||||
this->read_byte = mxc_nand_read_byte;
|
||||
this->read_word = mxc_nand_read_word;
|
||||
this->write_buf = mxc_nand_write_buf;
|
||||
this->read_buf = mxc_nand_read_buf;
|
||||
this->set_features = mxc_nand_set_features;
|
||||
this->get_features = mxc_nand_get_features;
|
||||
this->legacy.dev_ready = mxc_nand_dev_ready;
|
||||
this->legacy.cmdfunc = mxc_nand_command;
|
||||
this->legacy.read_byte = mxc_nand_read_byte;
|
||||
this->legacy.write_buf = mxc_nand_write_buf;
|
||||
this->legacy.read_buf = mxc_nand_read_buf;
|
||||
this->legacy.set_features = mxc_nand_set_features;
|
||||
this->legacy.get_features = mxc_nand_get_features;
|
||||
|
||||
host->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(host->clk))
|
||||
|
@ -1900,7 +1882,7 @@ static int mxcnd_probe(struct platform_device *pdev)
|
|||
|
||||
/* Scan the NAND device */
|
||||
this->dummy_controller.ops = &mxcnd_controller_ops;
|
||||
err = nand_scan(mtd, is_imx25_nfc(host) ? 4 : 1);
|
||||
err = nand_scan(this, is_imx25_nfc(host) ? 4 : 1);
|
||||
if (err)
|
||||
goto escan;
|
||||
|
||||
|
@ -1928,7 +1910,7 @@ static int mxcnd_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct mxc_nand_host *host = platform_get_drvdata(pdev);
|
||||
|
||||
nand_release(nand_to_mtd(&host->nand));
|
||||
nand_release(&host->nand);
|
||||
if (host->clk_act)
|
||||
clk_disable_unprepare(host->clk);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include "internals.h"
|
||||
|
||||
static void amd_nand_decode_id(struct nand_chip *chip)
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -61,13 +61,14 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/bbm.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
#define BBT_BLOCK_GOOD 0x00
|
||||
#define BBT_BLOCK_WORN 0x01
|
||||
#define BBT_BLOCK_RESERVED 0x02
|
||||
|
@ -683,14 +684,13 @@ static void mark_bbt_block_bad(struct nand_chip *this,
|
|||
struct nand_bbt_descr *td,
|
||||
int chip, int block)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(this);
|
||||
loff_t to;
|
||||
int res;
|
||||
|
||||
bbt_mark_entry(this, block, BBT_BLOCK_WORN);
|
||||
|
||||
to = (loff_t)block << this->bbt_erase_shift;
|
||||
res = this->block_markbad(mtd, to);
|
||||
res = nand_markbad_bbm(this, to);
|
||||
if (res)
|
||||
pr_warn("nand_bbt: error %d while marking block %d bad\n",
|
||||
res, block);
|
||||
|
@ -854,7 +854,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
|||
memset(&einfo, 0, sizeof(einfo));
|
||||
einfo.addr = to;
|
||||
einfo.len = 1 << this->bbt_erase_shift;
|
||||
res = nand_erase_nand(mtd, &einfo, 1);
|
||||
res = nand_erase_nand(this, &einfo, 1);
|
||||
if (res < 0) {
|
||||
pr_warn("nand_bbt: error while erasing BBT block %d\n",
|
||||
res);
|
||||
|
@ -1388,12 +1388,11 @@ EXPORT_SYMBOL(nand_create_bbt);
|
|||
|
||||
/**
|
||||
* nand_isreserved_bbt - [NAND Interface] Check if a block is reserved
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
* @offs: offset in the device
|
||||
*/
|
||||
int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
|
||||
int nand_isreserved_bbt(struct nand_chip *this, loff_t offs)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int block;
|
||||
|
||||
block = (int)(offs >> this->bbt_erase_shift);
|
||||
|
@ -1402,13 +1401,12 @@ int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
|
|||
|
||||
/**
|
||||
* nand_isbad_bbt - [NAND Interface] Check if a block is bad
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
* @offs: offset in the device
|
||||
* @allowbbt: allow access to bad block table region
|
||||
*/
|
||||
int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
|
||||
int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
int block, res;
|
||||
|
||||
block = (int)(offs >> this->bbt_erase_shift);
|
||||
|
@ -1430,12 +1428,12 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
|
|||
|
||||
/**
|
||||
* nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
* @offs: offset of the bad block
|
||||
*/
|
||||
int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
|
||||
int nand_markbad_bbt(struct nand_chip *this, loff_t offs)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(this);
|
||||
int block, ret = 0;
|
||||
|
||||
block = (int)(offs >> this->bbt_erase_shift);
|
||||
|
|
|
@ -43,14 +43,13 @@ struct nand_bch_control {
|
|||
|
||||
/**
|
||||
* nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
|
||||
* @mtd: MTD block structure
|
||||
* @chip: NAND chip object
|
||||
* @buf: input buffer with raw data
|
||||
* @code: output buffer with ECC
|
||||
*/
|
||||
int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
|
||||
int nand_bch_calculate_ecc(struct nand_chip *chip, const unsigned char *buf,
|
||||
unsigned char *code)
|
||||
{
|
||||
const struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nand_bch_control *nbc = chip->ecc.priv;
|
||||
unsigned int i;
|
||||
|
||||
|
@ -67,17 +66,16 @@ EXPORT_SYMBOL(nand_bch_calculate_ecc);
|
|||
|
||||
/**
|
||||
* nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
|
||||
* @mtd: MTD block structure
|
||||
* @chip: NAND chip object
|
||||
* @buf: raw data read from the chip
|
||||
* @read_ecc: ECC from the chip
|
||||
* @calc_ecc: the ECC calculated from raw data
|
||||
*
|
||||
* Detect and correct bit errors for a data byte block
|
||||
*/
|
||||
int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||
int nand_bch_correct_data(struct nand_chip *chip, unsigned char *buf,
|
||||
unsigned char *read_ecc, unsigned char *calc_ecc)
|
||||
{
|
||||
const struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nand_bch_control *nbc = chip->ecc.priv;
|
||||
unsigned int *errloc = nbc->errloc;
|
||||
int i, count;
|
||||
|
|
|
@ -132,9 +132,10 @@ static const char addressbits[256] = {
|
|||
* @buf: input buffer with raw data
|
||||
* @eccsize: data bytes per ECC step (256 or 512)
|
||||
* @code: output buffer with ECC
|
||||
* @sm_order: Smart Media byte ordering
|
||||
*/
|
||||
void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
|
||||
unsigned char *code)
|
||||
unsigned char *code, bool sm_order)
|
||||
{
|
||||
int i;
|
||||
const uint32_t *bp = (uint32_t *)buf;
|
||||
|
@ -330,45 +331,26 @@ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
|
|||
* possible, but benchmarks showed that on the system this is developed
|
||||
* the code below is the fastest
|
||||
*/
|
||||
#ifdef CONFIG_MTD_NAND_ECC_SMC
|
||||
code[0] =
|
||||
(invparity[rp7] << 7) |
|
||||
(invparity[rp6] << 6) |
|
||||
(invparity[rp5] << 5) |
|
||||
(invparity[rp4] << 4) |
|
||||
(invparity[rp3] << 3) |
|
||||
(invparity[rp2] << 2) |
|
||||
(invparity[rp1] << 1) |
|
||||
(invparity[rp0]);
|
||||
code[1] =
|
||||
(invparity[rp15] << 7) |
|
||||
(invparity[rp14] << 6) |
|
||||
(invparity[rp13] << 5) |
|
||||
(invparity[rp12] << 4) |
|
||||
(invparity[rp11] << 3) |
|
||||
(invparity[rp10] << 2) |
|
||||
(invparity[rp9] << 1) |
|
||||
(invparity[rp8]);
|
||||
#else
|
||||
code[1] =
|
||||
(invparity[rp7] << 7) |
|
||||
(invparity[rp6] << 6) |
|
||||
(invparity[rp5] << 5) |
|
||||
(invparity[rp4] << 4) |
|
||||
(invparity[rp3] << 3) |
|
||||
(invparity[rp2] << 2) |
|
||||
(invparity[rp1] << 1) |
|
||||
(invparity[rp0]);
|
||||
code[0] =
|
||||
(invparity[rp15] << 7) |
|
||||
(invparity[rp14] << 6) |
|
||||
(invparity[rp13] << 5) |
|
||||
(invparity[rp12] << 4) |
|
||||
(invparity[rp11] << 3) |
|
||||
(invparity[rp10] << 2) |
|
||||
(invparity[rp9] << 1) |
|
||||
(invparity[rp8]);
|
||||
#endif
|
||||
if (sm_order) {
|
||||
code[0] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
|
||||
(invparity[rp5] << 5) | (invparity[rp4] << 4) |
|
||||
(invparity[rp3] << 3) | (invparity[rp2] << 2) |
|
||||
(invparity[rp1] << 1) | (invparity[rp0]);
|
||||
code[1] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
|
||||
(invparity[rp13] << 5) | (invparity[rp12] << 4) |
|
||||
(invparity[rp11] << 3) | (invparity[rp10] << 2) |
|
||||
(invparity[rp9] << 1) | (invparity[rp8]);
|
||||
} else {
|
||||
code[1] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
|
||||
(invparity[rp5] << 5) | (invparity[rp4] << 4) |
|
||||
(invparity[rp3] << 3) | (invparity[rp2] << 2) |
|
||||
(invparity[rp1] << 1) | (invparity[rp0]);
|
||||
code[0] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
|
||||
(invparity[rp13] << 5) | (invparity[rp12] << 4) |
|
||||
(invparity[rp11] << 3) | (invparity[rp10] << 2) |
|
||||
(invparity[rp9] << 1) | (invparity[rp8]);
|
||||
}
|
||||
|
||||
if (eccsize_mult == 1)
|
||||
code[2] =
|
||||
(invparity[par & 0xf0] << 7) |
|
||||
|
@ -394,15 +376,16 @@ EXPORT_SYMBOL(__nand_calculate_ecc);
|
|||
/**
|
||||
* nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
|
||||
* block
|
||||
* @mtd: MTD block structure
|
||||
* @chip: NAND chip object
|
||||
* @buf: input buffer with raw data
|
||||
* @code: output buffer with ECC
|
||||
*/
|
||||
int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
|
||||
int nand_calculate_ecc(struct nand_chip *chip, const unsigned char *buf,
|
||||
unsigned char *code)
|
||||
{
|
||||
__nand_calculate_ecc(buf,
|
||||
mtd_to_nand(mtd)->ecc.size, code);
|
||||
bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
|
||||
|
||||
__nand_calculate_ecc(buf, chip->ecc.size, code, sm_order);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -414,12 +397,13 @@ EXPORT_SYMBOL(nand_calculate_ecc);
|
|||
* @read_ecc: ECC from the chip
|
||||
* @calc_ecc: the ECC calculated from raw data
|
||||
* @eccsize: data bytes per ECC step (256 or 512)
|
||||
* @sm_order: Smart Media byte order
|
||||
*
|
||||
* Detect and correct a 1 bit error for eccsize byte block
|
||||
*/
|
||||
int __nand_correct_data(unsigned char *buf,
|
||||
unsigned char *read_ecc, unsigned char *calc_ecc,
|
||||
unsigned int eccsize)
|
||||
unsigned int eccsize, bool sm_order)
|
||||
{
|
||||
unsigned char b0, b1, b2, bit_addr;
|
||||
unsigned int byte_addr;
|
||||
|
@ -431,13 +415,14 @@ int __nand_correct_data(unsigned char *buf,
|
|||
* we might need the xor result more than once,
|
||||
* so keep them in a local var
|
||||
*/
|
||||
#ifdef CONFIG_MTD_NAND_ECC_SMC
|
||||
if (sm_order) {
|
||||
b0 = read_ecc[0] ^ calc_ecc[0];
|
||||
b1 = read_ecc[1] ^ calc_ecc[1];
|
||||
#else
|
||||
} else {
|
||||
b0 = read_ecc[1] ^ calc_ecc[1];
|
||||
b1 = read_ecc[0] ^ calc_ecc[0];
|
||||
#endif
|
||||
}
|
||||
|
||||
b2 = read_ecc[2] ^ calc_ecc[2];
|
||||
|
||||
/* check if there are any bitfaults */
|
||||
|
@ -491,18 +476,20 @@ EXPORT_SYMBOL(__nand_correct_data);
|
|||
|
||||
/**
|
||||
* nand_correct_data - [NAND Interface] Detect and correct bit error(s)
|
||||
* @mtd: MTD block structure
|
||||
* @chip: NAND chip object
|
||||
* @buf: raw data read from the chip
|
||||
* @read_ecc: ECC from the chip
|
||||
* @calc_ecc: the ECC calculated from raw data
|
||||
*
|
||||
* Detect and correct a 1 bit error for 256/512 byte block
|
||||
*/
|
||||
int nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||
int nand_correct_data(struct nand_chip *chip, unsigned char *buf,
|
||||
unsigned char *read_ecc, unsigned char *calc_ecc)
|
||||
{
|
||||
return __nand_correct_data(buf, read_ecc, calc_ecc,
|
||||
mtd_to_nand(mtd)->ecc.size);
|
||||
bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
|
||||
|
||||
return __nand_correct_data(buf, read_ecc, calc_ecc, chip->ecc.size,
|
||||
sm_order);
|
||||
}
|
||||
EXPORT_SYMBOL(nand_correct_data);
|
||||
|
||||
|
|
47
drivers/mtd/nand/raw/nand_esmt.c
Normal file
47
drivers/mtd/nand/raw/nand_esmt.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2018 Toradex AG
|
||||
*
|
||||
* Author: Marcel Ziswiler <marcel.ziswiler@toradex.com>
|
||||
*/
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include "internals.h"
|
||||
|
||||
static void esmt_nand_decode_id(struct nand_chip *chip)
|
||||
{
|
||||
nand_decode_ext_id(chip);
|
||||
|
||||
/* Extract ECC requirements from 5th id byte. */
|
||||
if (chip->id.len >= 5 && nand_is_slc(chip)) {
|
||||
chip->ecc_step_ds = 512;
|
||||
switch (chip->id.data[4] & 0x3) {
|
||||
case 0x0:
|
||||
chip->ecc_strength_ds = 4;
|
||||
break;
|
||||
case 0x1:
|
||||
chip->ecc_strength_ds = 2;
|
||||
break;
|
||||
case 0x2:
|
||||
chip->ecc_strength_ds = 1;
|
||||
break;
|
||||
default:
|
||||
WARN(1, "Could not get ECC info");
|
||||
chip->ecc_step_ds = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int esmt_nand_init(struct nand_chip *chip)
|
||||
{
|
||||
if (nand_is_slc(chip))
|
||||
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct nand_manufacturer_ops esmt_nand_manuf_ops = {
|
||||
.detect = esmt_nand_decode_id,
|
||||
.init = esmt_nand_init,
|
||||
};
|
|
@ -15,10 +15,11 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
#define NAND_HYNIX_CMD_SET_PARAMS 0x36
|
||||
#define NAND_HYNIX_CMD_APPLY_PARAMS 0x16
|
||||
|
||||
|
@ -79,8 +80,6 @@ static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
|
|||
|
||||
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),
|
||||
|
@ -90,14 +89,13 @@ static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
|
|||
return nand_exec_op(chip, &op);
|
||||
}
|
||||
|
||||
chip->cmdfunc(mtd, cmd, -1, -1);
|
||||
chip->legacy.cmdfunc(chip, 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);
|
||||
u16 column = ((u16)addr << 8) | addr;
|
||||
|
||||
if (chip->exec_op) {
|
||||
|
@ -110,15 +108,14 @@ static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val)
|
|||
return nand_exec_op(chip, &op);
|
||||
}
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
|
||||
chip->write_byte(mtd, val);
|
||||
chip->legacy.cmdfunc(chip, NAND_CMD_NONE, column, -1);
|
||||
chip->legacy.write_byte(chip, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hynix_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
|
||||
static int hynix_nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct hynix_nand *hynix = nand_get_manufacturer_data(chip);
|
||||
const u8 *values;
|
||||
int i, ret;
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
#define LP_OPTIONS 0
|
||||
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
|
||||
|
||||
|
@ -169,21 +171,21 @@ struct nand_flash_dev nand_flash_ids[] = {
|
|||
|
||||
/* Manufacturer IDs */
|
||||
static const struct nand_manufacturer nand_manufacturers[] = {
|
||||
{NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
|
||||
{NAND_MFR_ESMT, "ESMT"},
|
||||
{NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
|
||||
{NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
|
||||
{NAND_MFR_ATO, "ATO"},
|
||||
{NAND_MFR_EON, "Eon"},
|
||||
{NAND_MFR_ESMT, "ESMT", &esmt_nand_manuf_ops},
|
||||
{NAND_MFR_FUJITSU, "Fujitsu"},
|
||||
{NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops},
|
||||
{NAND_MFR_INTEL, "Intel"},
|
||||
{NAND_MFR_MACRONIX, "Macronix", ¯onix_nand_manuf_ops},
|
||||
{NAND_MFR_MICRON, "Micron", µn_nand_manuf_ops},
|
||||
{NAND_MFR_NATIONAL, "National"},
|
||||
{NAND_MFR_RENESAS, "Renesas"},
|
||||
{NAND_MFR_STMICRO, "ST Micro"},
|
||||
{NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops},
|
||||
{NAND_MFR_MICRON, "Micron", µn_nand_manuf_ops},
|
||||
{NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
|
||||
{NAND_MFR_MACRONIX, "Macronix", ¯onix_nand_manuf_ops},
|
||||
{NAND_MFR_EON, "Eon"},
|
||||
{NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
|
||||
{NAND_MFR_SANDISK, "SanDisk"},
|
||||
{NAND_MFR_INTEL, "Intel"},
|
||||
{NAND_MFR_ATO, "ATO"},
|
||||
{NAND_MFR_STMICRO, "ST Micro"},
|
||||
{NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
|
||||
{NAND_MFR_WINBOND, "Winbond"},
|
||||
};
|
||||
|
||||
|
|
113
drivers/mtd/nand/raw/nand_jedec.c
Normal file
113
drivers/mtd/nand/raw/nand_jedec.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
|
||||
* 2002-2006 Thomas Gleixner (tglx@linutronix.de)
|
||||
*
|
||||
* Credits:
|
||||
* David Woodhouse for adding multichip support
|
||||
*
|
||||
* Aleph One Ltd. and Toby Churchill Ltd. for supporting the
|
||||
* rework for 2K page size chips
|
||||
*
|
||||
* This file contains all ONFI helpers.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
/*
|
||||
* Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
|
||||
*/
|
||||
int nand_jedec_detect(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct nand_jedec_params *p;
|
||||
struct jedec_ecc_info *ecc;
|
||||
int jedec_version = 0;
|
||||
char id[5];
|
||||
int i, val, ret;
|
||||
|
||||
/* Try JEDEC for unknown chip or LP */
|
||||
ret = nand_readid_op(chip, 0x40, id, sizeof(id));
|
||||
if (ret || strncmp(id, "JEDEC", sizeof(id)))
|
||||
return 0;
|
||||
|
||||
/* JEDEC chip: allocate a buffer to hold its parameter page */
|
||||
p = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
|
||||
if (ret) {
|
||||
ret = 0;
|
||||
goto free_jedec_param_page;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
ret = nand_read_data_op(chip, p, sizeof(*p), true);
|
||||
if (ret) {
|
||||
ret = 0;
|
||||
goto free_jedec_param_page;
|
||||
}
|
||||
|
||||
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
|
||||
le16_to_cpu(p->crc))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 3) {
|
||||
pr_err("Could not find valid JEDEC parameter page; aborting\n");
|
||||
goto free_jedec_param_page;
|
||||
}
|
||||
|
||||
/* Check version */
|
||||
val = le16_to_cpu(p->revision);
|
||||
if (val & (1 << 2))
|
||||
jedec_version = 10;
|
||||
else if (val & (1 << 1))
|
||||
jedec_version = 1; /* vendor specific version */
|
||||
|
||||
if (!jedec_version) {
|
||||
pr_info("unsupported JEDEC version: %d\n", val);
|
||||
goto free_jedec_param_page;
|
||||
}
|
||||
|
||||
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
|
||||
sanitize_string(p->model, sizeof(p->model));
|
||||
chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
|
||||
if (!chip->parameters.model) {
|
||||
ret = -ENOMEM;
|
||||
goto free_jedec_param_page;
|
||||
}
|
||||
|
||||
mtd->writesize = le32_to_cpu(p->byte_per_page);
|
||||
|
||||
/* Please reference to the comment for nand_flash_detect_onfi. */
|
||||
mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
|
||||
mtd->erasesize *= mtd->writesize;
|
||||
|
||||
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
||||
|
||||
/* Please reference to the comment for nand_flash_detect_onfi. */
|
||||
chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
|
||||
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
|
||||
chip->bits_per_cell = p->bits_per_cell;
|
||||
|
||||
if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS)
|
||||
chip->options |= NAND_BUSWIDTH_16;
|
||||
|
||||
/* ECC info */
|
||||
ecc = &p->ecc_info[0];
|
||||
|
||||
if (ecc->codeword_size >= 9) {
|
||||
chip->ecc_strength_ds = ecc->ecc_bits;
|
||||
chip->ecc_step_ds = 1 << ecc->codeword_size;
|
||||
} else {
|
||||
pr_warn("Invalid codeword size\n");
|
||||
}
|
||||
|
||||
free_jedec_param_page:
|
||||
kfree(p);
|
||||
return ret;
|
||||
}
|
642
drivers/mtd/nand/raw/nand_legacy.c
Normal file
642
drivers/mtd/nand/raw/nand_legacy.c
Normal file
|
@ -0,0 +1,642 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
|
||||
* 2002-2006 Thomas Gleixner (tglx@linutronix.de)
|
||||
*
|
||||
* Credits:
|
||||
* David Woodhouse for adding multichip support
|
||||
*
|
||||
* Aleph One Ltd. and Toby Churchill Ltd. for supporting the
|
||||
* rework for 2K page size chips
|
||||
*
|
||||
* This file contains all legacy helpers/code that should be removed
|
||||
* at some point.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/nmi.h>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
/**
|
||||
* nand_read_byte - [DEFAULT] read one byte from the chip
|
||||
* @chip: NAND chip object
|
||||
*
|
||||
* Default read function for 8bit buswidth
|
||||
*/
|
||||
static uint8_t nand_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
return readb(chip->legacy.IO_ADDR_R);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
|
||||
* @chip: NAND chip object
|
||||
*
|
||||
* Default read function for 16bit buswidth with endianness conversion.
|
||||
*
|
||||
*/
|
||||
static uint8_t nand_read_byte16(struct nand_chip *chip)
|
||||
{
|
||||
return (uint8_t) cpu_to_le16(readw(chip->legacy.IO_ADDR_R));
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_select_chip - [DEFAULT] control CE line
|
||||
* @chip: NAND chip object
|
||||
* @chipnr: chipnumber to select, -1 for deselect
|
||||
*
|
||||
* Default select function for 1 chip devices.
|
||||
*/
|
||||
static void nand_select_chip(struct nand_chip *chip, int chipnr)
|
||||
{
|
||||
switch (chipnr) {
|
||||
case -1:
|
||||
chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
|
||||
0 | NAND_CTRL_CHANGE);
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_write_byte - [DEFAULT] write single byte to chip
|
||||
* @chip: NAND chip object
|
||||
* @byte: value to write
|
||||
*
|
||||
* Default function to write a byte to I/O[7:0]
|
||||
*/
|
||||
static void nand_write_byte(struct nand_chip *chip, uint8_t byte)
|
||||
{
|
||||
chip->legacy.write_buf(chip, &byte, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
|
||||
* @chip: NAND chip object
|
||||
* @byte: value to write
|
||||
*
|
||||
* Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
|
||||
*/
|
||||
static void nand_write_byte16(struct nand_chip *chip, uint8_t byte)
|
||||
{
|
||||
uint16_t word = byte;
|
||||
|
||||
/*
|
||||
* It's not entirely clear what should happen to I/O[15:8] when writing
|
||||
* a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
|
||||
*
|
||||
* When the host supports a 16-bit bus width, only data is
|
||||
* transferred at the 16-bit width. All address and command line
|
||||
* transfers shall use only the lower 8-bits of the data bus. During
|
||||
* command transfers, the host may place any value on the upper
|
||||
* 8-bits of the data bus. During address transfers, the host shall
|
||||
* set the upper 8-bits of the data bus to 00h.
|
||||
*
|
||||
* One user of the write_byte callback is nand_set_features. The
|
||||
* four parameters are specified to be written to I/O[7:0], but this is
|
||||
* neither an address nor a command transfer. Let's assume a 0 on the
|
||||
* upper I/O lines is OK.
|
||||
*/
|
||||
chip->legacy.write_buf(chip, (uint8_t *)&word, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_write_buf - [DEFAULT] write buffer to chip
|
||||
* @chip: NAND chip object
|
||||
* @buf: data buffer
|
||||
* @len: number of bytes to write
|
||||
*
|
||||
* Default write function for 8bit buswidth.
|
||||
*/
|
||||
static void nand_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
|
||||
{
|
||||
iowrite8_rep(chip->legacy.IO_ADDR_W, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_read_buf - [DEFAULT] read chip data into buffer
|
||||
* @chip: NAND chip object
|
||||
* @buf: buffer to store date
|
||||
* @len: number of bytes to read
|
||||
*
|
||||
* Default read function for 8bit buswidth.
|
||||
*/
|
||||
static void nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
ioread8_rep(chip->legacy.IO_ADDR_R, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_write_buf16 - [DEFAULT] write buffer to chip
|
||||
* @chip: NAND chip object
|
||||
* @buf: data buffer
|
||||
* @len: number of bytes to write
|
||||
*
|
||||
* Default write function for 16bit buswidth.
|
||||
*/
|
||||
static void nand_write_buf16(struct nand_chip *chip, const uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
u16 *p = (u16 *) buf;
|
||||
|
||||
iowrite16_rep(chip->legacy.IO_ADDR_W, p, len >> 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_read_buf16 - [DEFAULT] read chip data into buffer
|
||||
* @chip: NAND chip object
|
||||
* @buf: buffer to store date
|
||||
* @len: number of bytes to read
|
||||
*
|
||||
* Default read function for 16bit buswidth.
|
||||
*/
|
||||
static void nand_read_buf16(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
u16 *p = (u16 *) buf;
|
||||
|
||||
ioread16_rep(chip->legacy.IO_ADDR_R, p, len >> 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
|
||||
* @mtd: MTD device structure
|
||||
* @timeo: Timeout
|
||||
*
|
||||
* Helper function for nand_wait_ready used when needing to wait in interrupt
|
||||
* context.
|
||||
*/
|
||||
static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
int i;
|
||||
|
||||
/* Wait for the device to get ready */
|
||||
for (i = 0; i < timeo; i++) {
|
||||
if (chip->legacy.dev_ready(chip))
|
||||
break;
|
||||
touch_softlockup_watchdog();
|
||||
mdelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
|
||||
* @chip: NAND chip object
|
||||
*
|
||||
* Wait for the ready pin after a command, and warn if a timeout occurs.
|
||||
*/
|
||||
void nand_wait_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
unsigned long timeo = 400;
|
||||
|
||||
if (in_interrupt() || oops_in_progress)
|
||||
return panic_nand_wait_ready(mtd, timeo);
|
||||
|
||||
/* Wait until command is processed or timeout occurs */
|
||||
timeo = jiffies + msecs_to_jiffies(timeo);
|
||||
do {
|
||||
if (chip->legacy.dev_ready(chip))
|
||||
return;
|
||||
cond_resched();
|
||||
} while (time_before(jiffies, timeo));
|
||||
|
||||
if (!chip->legacy.dev_ready(chip))
|
||||
pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nand_wait_ready);
|
||||
|
||||
/**
|
||||
* nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
|
||||
* @mtd: MTD device structure
|
||||
* @timeo: Timeout in ms
|
||||
*
|
||||
* Wait for status ready (i.e. command done) or timeout.
|
||||
*/
|
||||
static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
|
||||
{
|
||||
register struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
int ret;
|
||||
|
||||
timeo = jiffies + msecs_to_jiffies(timeo);
|
||||
do {
|
||||
u8 status;
|
||||
|
||||
ret = nand_read_data_op(chip, &status, sizeof(status), true);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
if (status & NAND_STATUS_READY)
|
||||
break;
|
||||
touch_softlockup_watchdog();
|
||||
} while (time_before(jiffies, timeo));
|
||||
};
|
||||
|
||||
/**
|
||||
* nand_command - [DEFAULT] Send command to NAND device
|
||||
* @chip: NAND chip object
|
||||
* @command: the command to be sent
|
||||
* @column: the column address for this command, -1 if none
|
||||
* @page_addr: the page address for this command, -1 if none
|
||||
*
|
||||
* Send command to NAND device. This function is used for small page devices
|
||||
* (512 Bytes per page).
|
||||
*/
|
||||
static void nand_command(struct nand_chip *chip, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
|
||||
|
||||
/* Write out the command to the device */
|
||||
if (command == NAND_CMD_SEQIN) {
|
||||
int readcmd;
|
||||
|
||||
if (column >= mtd->writesize) {
|
||||
/* OOB area */
|
||||
column -= mtd->writesize;
|
||||
readcmd = NAND_CMD_READOOB;
|
||||
} else if (column < 256) {
|
||||
/* First 256 bytes --> READ0 */
|
||||
readcmd = NAND_CMD_READ0;
|
||||
} else {
|
||||
column -= 256;
|
||||
readcmd = NAND_CMD_READ1;
|
||||
}
|
||||
chip->legacy.cmd_ctrl(chip, readcmd, ctrl);
|
||||
ctrl &= ~NAND_CTRL_CHANGE;
|
||||
}
|
||||
if (command != NAND_CMD_NONE)
|
||||
chip->legacy.cmd_ctrl(chip, command, ctrl);
|
||||
|
||||
/* Address cycle, when necessary */
|
||||
ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
|
||||
/* Serially input address */
|
||||
if (column != -1) {
|
||||
/* Adjust columns for 16 bit buswidth */
|
||||
if (chip->options & NAND_BUSWIDTH_16 &&
|
||||
!nand_opcode_8bits(command))
|
||||
column >>= 1;
|
||||
chip->legacy.cmd_ctrl(chip, column, ctrl);
|
||||
ctrl &= ~NAND_CTRL_CHANGE;
|
||||
}
|
||||
if (page_addr != -1) {
|
||||
chip->legacy.cmd_ctrl(chip, page_addr, ctrl);
|
||||
ctrl &= ~NAND_CTRL_CHANGE;
|
||||
chip->legacy.cmd_ctrl(chip, page_addr >> 8, ctrl);
|
||||
if (chip->options & NAND_ROW_ADDR_3)
|
||||
chip->legacy.cmd_ctrl(chip, page_addr >> 16, ctrl);
|
||||
}
|
||||
chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
|
||||
NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
/*
|
||||
* Program and erase have their own busy handlers status and sequential
|
||||
* in needs no delay
|
||||
*/
|
||||
switch (command) {
|
||||
|
||||
case NAND_CMD_NONE:
|
||||
case NAND_CMD_PAGEPROG:
|
||||
case NAND_CMD_ERASE1:
|
||||
case NAND_CMD_ERASE2:
|
||||
case NAND_CMD_SEQIN:
|
||||
case NAND_CMD_STATUS:
|
||||
case NAND_CMD_READID:
|
||||
case NAND_CMD_SET_FEATURES:
|
||||
return;
|
||||
|
||||
case NAND_CMD_RESET:
|
||||
if (chip->legacy.dev_ready)
|
||||
break;
|
||||
udelay(chip->legacy.chip_delay);
|
||||
chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS,
|
||||
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
|
||||
chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
|
||||
NAND_NCE | NAND_CTRL_CHANGE);
|
||||
/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
|
||||
nand_wait_status_ready(mtd, 250);
|
||||
return;
|
||||
|
||||
/* This applies to read commands */
|
||||
case NAND_CMD_READ0:
|
||||
/*
|
||||
* READ0 is sometimes used to exit GET STATUS mode. When this
|
||||
* is the case no address cycles are requested, and we can use
|
||||
* this information to detect that we should not wait for the
|
||||
* device to be ready.
|
||||
*/
|
||||
if (column == -1 && page_addr == -1)
|
||||
return;
|
||||
|
||||
default:
|
||||
/*
|
||||
* If we don't have access to the busy pin, we apply the given
|
||||
* command delay
|
||||
*/
|
||||
if (!chip->legacy.dev_ready) {
|
||||
udelay(chip->legacy.chip_delay);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Apply this short delay always to ensure that we do wait tWB in
|
||||
* any case on any machine.
|
||||
*/
|
||||
ndelay(100);
|
||||
|
||||
nand_wait_ready(chip);
|
||||
}
|
||||
|
||||
static void nand_ccs_delay(struct nand_chip *chip)
|
||||
{
|
||||
/*
|
||||
* The controller already takes care of waiting for tCCS when the RNDIN
|
||||
* or RNDOUT command is sent, return directly.
|
||||
*/
|
||||
if (!(chip->options & NAND_WAIT_TCCS))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Wait tCCS_min if it is correctly defined, otherwise wait 500ns
|
||||
* (which should be safe for all NANDs).
|
||||
*/
|
||||
if (chip->setup_data_interface)
|
||||
ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000);
|
||||
else
|
||||
ndelay(500);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_command_lp - [DEFAULT] Send command to NAND large page device
|
||||
* @chip: NAND chip object
|
||||
* @command: the command to be sent
|
||||
* @column: the column address for this command, -1 if none
|
||||
* @page_addr: the page address for this command, -1 if none
|
||||
*
|
||||
* Send command to NAND device. This is the version for the new large page
|
||||
* devices. We don't have the separate regions as we have in the small page
|
||||
* devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
|
||||
*/
|
||||
static void nand_command_lp(struct nand_chip *chip, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
/* Emulate NAND_CMD_READOOB */
|
||||
if (command == NAND_CMD_READOOB) {
|
||||
column += mtd->writesize;
|
||||
command = NAND_CMD_READ0;
|
||||
}
|
||||
|
||||
/* Command latch cycle */
|
||||
if (command != NAND_CMD_NONE)
|
||||
chip->legacy.cmd_ctrl(chip, command,
|
||||
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
|
||||
|
||||
if (column != -1 || page_addr != -1) {
|
||||
int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
|
||||
|
||||
/* Serially input address */
|
||||
if (column != -1) {
|
||||
/* Adjust columns for 16 bit buswidth */
|
||||
if (chip->options & NAND_BUSWIDTH_16 &&
|
||||
!nand_opcode_8bits(command))
|
||||
column >>= 1;
|
||||
chip->legacy.cmd_ctrl(chip, column, ctrl);
|
||||
ctrl &= ~NAND_CTRL_CHANGE;
|
||||
|
||||
/* Only output a single addr cycle for 8bits opcodes. */
|
||||
if (!nand_opcode_8bits(command))
|
||||
chip->legacy.cmd_ctrl(chip, column >> 8, ctrl);
|
||||
}
|
||||
if (page_addr != -1) {
|
||||
chip->legacy.cmd_ctrl(chip, page_addr, ctrl);
|
||||
chip->legacy.cmd_ctrl(chip, page_addr >> 8,
|
||||
NAND_NCE | NAND_ALE);
|
||||
if (chip->options & NAND_ROW_ADDR_3)
|
||||
chip->legacy.cmd_ctrl(chip, page_addr >> 16,
|
||||
NAND_NCE | NAND_ALE);
|
||||
}
|
||||
}
|
||||
chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
|
||||
NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
/*
|
||||
* Program and erase have their own busy handlers status, sequential
|
||||
* in and status need no delay.
|
||||
*/
|
||||
switch (command) {
|
||||
|
||||
case NAND_CMD_NONE:
|
||||
case NAND_CMD_CACHEDPROG:
|
||||
case NAND_CMD_PAGEPROG:
|
||||
case NAND_CMD_ERASE1:
|
||||
case NAND_CMD_ERASE2:
|
||||
case NAND_CMD_SEQIN:
|
||||
case NAND_CMD_STATUS:
|
||||
case NAND_CMD_READID:
|
||||
case NAND_CMD_SET_FEATURES:
|
||||
return;
|
||||
|
||||
case NAND_CMD_RNDIN:
|
||||
nand_ccs_delay(chip);
|
||||
return;
|
||||
|
||||
case NAND_CMD_RESET:
|
||||
if (chip->legacy.dev_ready)
|
||||
break;
|
||||
udelay(chip->legacy.chip_delay);
|
||||
chip->legacy.cmd_ctrl(chip, NAND_CMD_STATUS,
|
||||
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
|
||||
chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
|
||||
NAND_NCE | NAND_CTRL_CHANGE);
|
||||
/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
|
||||
nand_wait_status_ready(mtd, 250);
|
||||
return;
|
||||
|
||||
case NAND_CMD_RNDOUT:
|
||||
/* No ready / busy check necessary */
|
||||
chip->legacy.cmd_ctrl(chip, NAND_CMD_RNDOUTSTART,
|
||||
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
|
||||
chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
|
||||
NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
nand_ccs_delay(chip);
|
||||
return;
|
||||
|
||||
case NAND_CMD_READ0:
|
||||
/*
|
||||
* READ0 is sometimes used to exit GET STATUS mode. When this
|
||||
* is the case no address cycles are requested, and we can use
|
||||
* this information to detect that READSTART should not be
|
||||
* issued.
|
||||
*/
|
||||
if (column == -1 && page_addr == -1)
|
||||
return;
|
||||
|
||||
chip->legacy.cmd_ctrl(chip, NAND_CMD_READSTART,
|
||||
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
|
||||
chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
|
||||
NAND_NCE | NAND_CTRL_CHANGE);
|
||||
|
||||
/* This applies to read commands */
|
||||
default:
|
||||
/*
|
||||
* If we don't have access to the busy pin, we apply the given
|
||||
* command delay.
|
||||
*/
|
||||
if (!chip->legacy.dev_ready) {
|
||||
udelay(chip->legacy.chip_delay);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply this short delay always to ensure that we do wait tWB in
|
||||
* any case on any machine.
|
||||
*/
|
||||
ndelay(100);
|
||||
|
||||
nand_wait_ready(chip);
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_get_set_features_notsupp - set/get features stub returning -ENOTSUPP
|
||||
* @chip: nand chip info structure
|
||||
* @addr: feature address.
|
||||
* @subfeature_param: the subfeature parameters, a four bytes array.
|
||||
*
|
||||
* Should be used by NAND controller drivers that do not support the SET/GET
|
||||
* FEATURES operations.
|
||||
*/
|
||||
int nand_get_set_features_notsupp(struct nand_chip *chip, int addr,
|
||||
u8 *subfeature_param)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
EXPORT_SYMBOL(nand_get_set_features_notsupp);
|
||||
|
||||
/**
|
||||
* nand_wait - [DEFAULT] wait until the command is done
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip structure
|
||||
*
|
||||
* Wait for command done. This applies to erase and program only.
|
||||
*/
|
||||
static int nand_wait(struct nand_chip *chip)
|
||||
{
|
||||
|
||||
unsigned long timeo = 400;
|
||||
u8 status;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Apply this short delay always to ensure that we do wait tWB in any
|
||||
* case on any machine.
|
||||
*/
|
||||
ndelay(100);
|
||||
|
||||
ret = nand_status_op(chip, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (in_interrupt() || oops_in_progress)
|
||||
panic_nand_wait(chip, timeo);
|
||||
else {
|
||||
timeo = jiffies + msecs_to_jiffies(timeo);
|
||||
do {
|
||||
if (chip->legacy.dev_ready) {
|
||||
if (chip->legacy.dev_ready(chip))
|
||||
break;
|
||||
} else {
|
||||
ret = nand_read_data_op(chip, &status,
|
||||
sizeof(status), true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (status & NAND_STATUS_READY)
|
||||
break;
|
||||
}
|
||||
cond_resched();
|
||||
} while (time_before(jiffies, timeo));
|
||||
}
|
||||
|
||||
ret = nand_read_data_op(chip, &status, sizeof(status), true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* This can happen if in case of timeout or buggy dev_ready */
|
||||
WARN_ON(!(status & NAND_STATUS_READY));
|
||||
return status;
|
||||
}
|
||||
|
||||
void nand_legacy_set_defaults(struct nand_chip *chip)
|
||||
{
|
||||
unsigned int busw = chip->options & NAND_BUSWIDTH_16;
|
||||
|
||||
if (chip->exec_op)
|
||||
return;
|
||||
|
||||
/* check for proper chip_delay setup, set 20us if not */
|
||||
if (!chip->legacy.chip_delay)
|
||||
chip->legacy.chip_delay = 20;
|
||||
|
||||
/* check, if a user supplied command function given */
|
||||
if (!chip->legacy.cmdfunc && !chip->exec_op)
|
||||
chip->legacy.cmdfunc = nand_command;
|
||||
|
||||
/* check, if a user supplied wait function given */
|
||||
if (chip->legacy.waitfunc == NULL)
|
||||
chip->legacy.waitfunc = nand_wait;
|
||||
|
||||
if (!chip->select_chip)
|
||||
chip->select_chip = nand_select_chip;
|
||||
|
||||
/* If called twice, pointers that depend on busw may need to be reset */
|
||||
if (!chip->legacy.read_byte || chip->legacy.read_byte == nand_read_byte)
|
||||
chip->legacy.read_byte = busw ? nand_read_byte16 : nand_read_byte;
|
||||
if (!chip->legacy.write_buf || chip->legacy.write_buf == nand_write_buf)
|
||||
chip->legacy.write_buf = busw ? nand_write_buf16 : nand_write_buf;
|
||||
if (!chip->legacy.write_byte || chip->legacy.write_byte == nand_write_byte)
|
||||
chip->legacy.write_byte = busw ? nand_write_byte16 : nand_write_byte;
|
||||
if (!chip->legacy.read_buf || chip->legacy.read_buf == nand_read_buf)
|
||||
chip->legacy.read_buf = busw ? nand_read_buf16 : nand_read_buf;
|
||||
}
|
||||
|
||||
void nand_legacy_adjust_cmdfunc(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
/* Do not replace user supplied command function! */
|
||||
if (mtd->writesize > 512 && chip->legacy.cmdfunc == nand_command)
|
||||
chip->legacy.cmdfunc = nand_command_lp;
|
||||
}
|
||||
|
||||
int nand_legacy_check_hooks(struct nand_chip *chip)
|
||||
{
|
||||
/*
|
||||
* ->legacy.cmdfunc() is legacy and will only be used if ->exec_op() is
|
||||
* not populated.
|
||||
*/
|
||||
if (chip->exec_op)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Default functions assigned for ->legacy.cmdfunc() and
|
||||
* ->select_chip() both expect ->legacy.cmd_ctrl() to be populated.
|
||||
*/
|
||||
if ((!chip->legacy.cmdfunc || !chip->select_chip) &&
|
||||
!chip->legacy.cmd_ctrl) {
|
||||
pr_err("->legacy.cmd_ctrl() should be provided\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include "internals.h"
|
||||
|
||||
/*
|
||||
* Macronix AC series does not support using SET/GET_FEATURES to change
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
/*
|
||||
* Special Micron status bit 3 indicates that the block has been
|
||||
* corrected by on-die ECC and should be rewritten.
|
||||
|
@ -74,9 +75,8 @@ struct micron_nand {
|
|||
struct micron_on_die_ecc ecc;
|
||||
};
|
||||
|
||||
static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
|
||||
static int micron_nand_setup_read_retry(struct nand_chip *chip, int retry_mode)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
|
||||
|
||||
return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature);
|
||||
|
@ -290,10 +290,10 @@ static int micron_nand_on_die_ecc_status_8(struct nand_chip *chip, u8 status)
|
|||
}
|
||||
|
||||
static int
|
||||
micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
micron_nand_read_page_on_die_ecc(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
u8 status;
|
||||
int ret, max_bitflips = 0;
|
||||
|
||||
|
@ -332,9 +332,8 @@ out:
|
|||
}
|
||||
|
||||
static int
|
||||
micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
micron_nand_write_page_on_die_ecc(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -342,7 +341,7 @@ micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nand_write_page_raw(mtd, chip, buf, oob_required, page);
|
||||
ret = nand_write_page_raw(chip, buf, oob_required, page);
|
||||
micron_nand_on_die_ecc_setup(chip, false);
|
||||
|
||||
return ret;
|
||||
|
|
305
drivers/mtd/nand/raw/nand_onfi.c
Normal file
305
drivers/mtd/nand/raw/nand_onfi.c
Normal file
|
@ -0,0 +1,305 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
|
||||
* 2002-2006 Thomas Gleixner (tglx@linutronix.de)
|
||||
*
|
||||
* Credits:
|
||||
* David Woodhouse for adding multichip support
|
||||
*
|
||||
* Aleph One Ltd. and Toby Churchill Ltd. for supporting the
|
||||
* rework for 2K page size chips
|
||||
*
|
||||
* This file contains all ONFI helpers.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
|
||||
{
|
||||
int i;
|
||||
while (len--) {
|
||||
crc ^= *p++ << 8;
|
||||
for (i = 0; i < 8; i++)
|
||||
crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* Parse the Extended Parameter Page. */
|
||||
static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
|
||||
struct nand_onfi_params *p)
|
||||
{
|
||||
struct onfi_ext_param_page *ep;
|
||||
struct onfi_ext_section *s;
|
||||
struct onfi_ext_ecc_info *ecc;
|
||||
uint8_t *cursor;
|
||||
int ret;
|
||||
int len;
|
||||
int i;
|
||||
|
||||
len = le16_to_cpu(p->ext_param_page_length) * 16;
|
||||
ep = kmalloc(len, GFP_KERNEL);
|
||||
if (!ep)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Send our own NAND_CMD_PARAM. */
|
||||
ret = nand_read_param_page_op(chip, 0, NULL, 0);
|
||||
if (ret)
|
||||
goto ext_out;
|
||||
|
||||
/* Use the Change Read Column command to skip the ONFI param pages. */
|
||||
ret = nand_change_read_column_op(chip,
|
||||
sizeof(*p) * p->num_of_param_pages,
|
||||
ep, len, true);
|
||||
if (ret)
|
||||
goto ext_out;
|
||||
|
||||
ret = -EINVAL;
|
||||
if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
|
||||
!= le16_to_cpu(ep->crc))) {
|
||||
pr_debug("fail in the CRC.\n");
|
||||
goto ext_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the signature.
|
||||
* Do not strictly follow the ONFI spec, maybe changed in future.
|
||||
*/
|
||||
if (strncmp(ep->sig, "EPPS", 4)) {
|
||||
pr_debug("The signature is invalid.\n");
|
||||
goto ext_out;
|
||||
}
|
||||
|
||||
/* find the ECC section. */
|
||||
cursor = (uint8_t *)(ep + 1);
|
||||
for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
|
||||
s = ep->sections + i;
|
||||
if (s->type == ONFI_SECTION_TYPE_2)
|
||||
break;
|
||||
cursor += s->length * 16;
|
||||
}
|
||||
if (i == ONFI_EXT_SECTION_MAX) {
|
||||
pr_debug("We can not find the ECC section.\n");
|
||||
goto ext_out;
|
||||
}
|
||||
|
||||
/* get the info we want. */
|
||||
ecc = (struct onfi_ext_ecc_info *)cursor;
|
||||
|
||||
if (!ecc->codeword_size) {
|
||||
pr_debug("Invalid codeword size\n");
|
||||
goto ext_out;
|
||||
}
|
||||
|
||||
chip->ecc_strength_ds = ecc->ecc_bits;
|
||||
chip->ecc_step_ds = 1 << ecc->codeword_size;
|
||||
ret = 0;
|
||||
|
||||
ext_out:
|
||||
kfree(ep);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recover data with bit-wise majority
|
||||
*/
|
||||
static void nand_bit_wise_majority(const void **srcbufs,
|
||||
unsigned int nsrcbufs,
|
||||
void *dstbuf,
|
||||
unsigned int bufsize)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
for (i = 0; i < bufsize; i++) {
|
||||
u8 val = 0;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
unsigned int cnt = 0;
|
||||
|
||||
for (k = 0; k < nsrcbufs; k++) {
|
||||
const u8 *srcbuf = srcbufs[k];
|
||||
|
||||
if (srcbuf[i] & BIT(j))
|
||||
cnt++;
|
||||
}
|
||||
|
||||
if (cnt > nsrcbufs / 2)
|
||||
val |= BIT(j);
|
||||
}
|
||||
|
||||
((u8 *)dstbuf)[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
|
||||
*/
|
||||
int nand_onfi_detect(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct nand_onfi_params *p;
|
||||
struct onfi_params *onfi;
|
||||
int onfi_version = 0;
|
||||
char id[4];
|
||||
int i, ret, val;
|
||||
|
||||
/* Try ONFI for unknown chip or LP */
|
||||
ret = nand_readid_op(chip, 0x20, id, sizeof(id));
|
||||
if (ret || strncmp(id, "ONFI", 4))
|
||||
return 0;
|
||||
|
||||
/* ONFI chip: allocate a buffer to hold its parameter page */
|
||||
p = kzalloc((sizeof(*p) * 3), GFP_KERNEL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = nand_read_param_page_op(chip, 0, NULL, 0);
|
||||
if (ret) {
|
||||
ret = 0;
|
||||
goto free_onfi_param_page;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
ret = nand_read_data_op(chip, &p[i], sizeof(*p), true);
|
||||
if (ret) {
|
||||
ret = 0;
|
||||
goto free_onfi_param_page;
|
||||
}
|
||||
|
||||
if (onfi_crc16(ONFI_CRC_BASE, (u8 *)&p[i], 254) ==
|
||||
le16_to_cpu(p->crc)) {
|
||||
if (i)
|
||||
memcpy(p, &p[i], sizeof(*p));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 3) {
|
||||
const void *srcbufs[3] = {p, p + 1, p + 2};
|
||||
|
||||
pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n");
|
||||
nand_bit_wise_majority(srcbufs, ARRAY_SIZE(srcbufs), p,
|
||||
sizeof(*p));
|
||||
|
||||
if (onfi_crc16(ONFI_CRC_BASE, (u8 *)p, 254) !=
|
||||
le16_to_cpu(p->crc)) {
|
||||
pr_err("ONFI parameter recovery failed, aborting\n");
|
||||
goto free_onfi_param_page;
|
||||
}
|
||||
}
|
||||
|
||||
if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
|
||||
chip->manufacturer.desc->ops->fixup_onfi_param_page)
|
||||
chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p);
|
||||
|
||||
/* Check version */
|
||||
val = le16_to_cpu(p->revision);
|
||||
if (val & ONFI_VERSION_2_3)
|
||||
onfi_version = 23;
|
||||
else if (val & ONFI_VERSION_2_2)
|
||||
onfi_version = 22;
|
||||
else if (val & ONFI_VERSION_2_1)
|
||||
onfi_version = 21;
|
||||
else if (val & ONFI_VERSION_2_0)
|
||||
onfi_version = 20;
|
||||
else if (val & ONFI_VERSION_1_0)
|
||||
onfi_version = 10;
|
||||
|
||||
if (!onfi_version) {
|
||||
pr_info("unsupported ONFI version: %d\n", val);
|
||||
goto free_onfi_param_page;
|
||||
}
|
||||
|
||||
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
|
||||
sanitize_string(p->model, sizeof(p->model));
|
||||
chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
|
||||
if (!chip->parameters.model) {
|
||||
ret = -ENOMEM;
|
||||
goto free_onfi_param_page;
|
||||
}
|
||||
|
||||
mtd->writesize = le32_to_cpu(p->byte_per_page);
|
||||
|
||||
/*
|
||||
* pages_per_block and blocks_per_lun may not be a power-of-2 size
|
||||
* (don't ask me who thought of this...). MTD assumes that these
|
||||
* dimensions will be power-of-2, so just truncate the remaining area.
|
||||
*/
|
||||
mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
|
||||
mtd->erasesize *= mtd->writesize;
|
||||
|
||||
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
||||
|
||||
/* See erasesize comment */
|
||||
chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
|
||||
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
|
||||
chip->bits_per_cell = p->bits_per_cell;
|
||||
|
||||
chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
|
||||
chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
|
||||
|
||||
if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS)
|
||||
chip->options |= NAND_BUSWIDTH_16;
|
||||
|
||||
if (p->ecc_bits != 0xff) {
|
||||
chip->ecc_strength_ds = p->ecc_bits;
|
||||
chip->ecc_step_ds = 512;
|
||||
} else if (onfi_version >= 21 &&
|
||||
(le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
|
||||
|
||||
/*
|
||||
* The nand_flash_detect_ext_param_page() uses the
|
||||
* Change Read Column command which maybe not supported
|
||||
* by the chip->legacy.cmdfunc. So try to update the
|
||||
* chip->legacy.cmdfunc now. We do not replace user supplied
|
||||
* command function.
|
||||
*/
|
||||
nand_legacy_adjust_cmdfunc(chip);
|
||||
|
||||
/* The Extended Parameter Page is supported since ONFI 2.1. */
|
||||
if (nand_flash_detect_ext_param_page(chip, p))
|
||||
pr_warn("Failed to detect ONFI extended param page\n");
|
||||
} else {
|
||||
pr_warn("Could not retrieve ONFI ECC requirements\n");
|
||||
}
|
||||
|
||||
/* Save some parameters from the parameter page for future use */
|
||||
if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) {
|
||||
chip->parameters.supports_set_get_features = true;
|
||||
bitmap_set(chip->parameters.get_feature_list,
|
||||
ONFI_FEATURE_ADDR_TIMING_MODE, 1);
|
||||
bitmap_set(chip->parameters.set_feature_list,
|
||||
ONFI_FEATURE_ADDR_TIMING_MODE, 1);
|
||||
}
|
||||
|
||||
onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
|
||||
if (!onfi) {
|
||||
ret = -ENOMEM;
|
||||
goto free_model;
|
||||
}
|
||||
|
||||
onfi->version = onfi_version;
|
||||
onfi->tPROG = le16_to_cpu(p->t_prog);
|
||||
onfi->tBERS = le16_to_cpu(p->t_bers);
|
||||
onfi->tR = le16_to_cpu(p->t_r);
|
||||
onfi->tCCS = le16_to_cpu(p->t_ccs);
|
||||
onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode);
|
||||
onfi->vendor_revision = le16_to_cpu(p->vendor_revision);
|
||||
memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
|
||||
chip->parameters.onfi = onfi;
|
||||
|
||||
/* Identification done, free the full ONFI parameter page and exit */
|
||||
kfree(p);
|
||||
|
||||
return 1;
|
||||
|
||||
free_model:
|
||||
kfree(chip->parameters.model);
|
||||
free_onfi_param_page:
|
||||
kfree(p);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include "internals.h"
|
||||
|
||||
static void samsung_nand_decode_id(struct nand_chip *chip)
|
||||
{
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
#define ONFI_DYN_TIMING_MAX U16_MAX
|
||||
|
||||
|
@ -270,20 +271,6 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
|
|||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND
|
||||
* timings according to the given ONFI timing mode
|
||||
* @mode: ONFI timing mode
|
||||
*/
|
||||
const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
|
||||
{
|
||||
if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return &onfi_sdr_timings[mode].timings.sdr;
|
||||
}
|
||||
EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
|
||||
|
||||
/**
|
||||
* onfi_fill_data_interface - [NAND Interface] Initialize a data interface from
|
||||
* given ONFI mode
|
||||
|
@ -339,4 +326,3 @@ int onfi_fill_data_interface(struct nand_chip *chip,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(onfi_fill_data_interface);
|
||||
|
|
|
@ -15,7 +15,88 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include "internals.h"
|
||||
|
||||
/* Bit for detecting BENAND */
|
||||
#define TOSHIBA_NAND_ID4_IS_BENAND BIT(7)
|
||||
|
||||
/* Recommended to rewrite for BENAND */
|
||||
#define TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED BIT(3)
|
||||
|
||||
static int toshiba_nand_benand_eccstatus(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
int ret;
|
||||
unsigned int max_bitflips = 0;
|
||||
u8 status;
|
||||
|
||||
/* Check Status */
|
||||
ret = nand_status_op(chip, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (status & NAND_STATUS_FAIL) {
|
||||
/* uncorrected */
|
||||
mtd->ecc_stats.failed++;
|
||||
} else if (status & TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED) {
|
||||
/* corrected */
|
||||
max_bitflips = mtd->bitflip_threshold;
|
||||
mtd->ecc_stats.corrected += max_bitflips;
|
||||
}
|
||||
|
||||
return max_bitflips;
|
||||
}
|
||||
|
||||
static int
|
||||
toshiba_nand_read_page_benand(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = nand_read_page_raw(chip, buf, oob_required, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return toshiba_nand_benand_eccstatus(chip);
|
||||
}
|
||||
|
||||
static int
|
||||
toshiba_nand_read_subpage_benand(struct nand_chip *chip, uint32_t data_offs,
|
||||
uint32_t readlen, uint8_t *bufpoi, int page)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = nand_read_page_op(chip, page, data_offs,
|
||||
bufpoi + data_offs, readlen);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return toshiba_nand_benand_eccstatus(chip);
|
||||
}
|
||||
|
||||
static void toshiba_nand_benand_init(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
/*
|
||||
* On BENAND, the entire OOB region can be used by the MTD user.
|
||||
* The calculated ECC bytes are stored into other isolated
|
||||
* area which is not accessible to users.
|
||||
* This is why chip->ecc.bytes = 0.
|
||||
*/
|
||||
chip->ecc.bytes = 0;
|
||||
chip->ecc.size = 512;
|
||||
chip->ecc.strength = 8;
|
||||
chip->ecc.read_page = toshiba_nand_read_page_benand;
|
||||
chip->ecc.read_subpage = toshiba_nand_read_subpage_benand;
|
||||
chip->ecc.write_page = nand_write_page_raw;
|
||||
chip->ecc.read_page_raw = nand_read_page_raw_notsupp;
|
||||
chip->ecc.write_page_raw = nand_write_page_raw_notsupp;
|
||||
|
||||
chip->options |= NAND_SUBPAGE_READ;
|
||||
|
||||
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
|
||||
}
|
||||
|
||||
static void toshiba_nand_decode_id(struct nand_chip *chip)
|
||||
{
|
||||
|
@ -68,6 +149,11 @@ static int toshiba_nand_init(struct nand_chip *chip)
|
|||
if (nand_is_slc(chip))
|
||||
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
|
||||
|
||||
/* Check that chip is BENAND and ECC mode is on-die */
|
||||
if (nand_is_slc(chip) && chip->ecc.mode == NAND_ECC_ON_DIE &&
|
||||
chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND)
|
||||
toshiba_nand_benand_init(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -656,7 +656,7 @@ static int __init init_nandsim(struct mtd_info *mtd)
|
|||
}
|
||||
|
||||
/* Force mtd to not do delays */
|
||||
chip->chip_delay = 0;
|
||||
chip->legacy.chip_delay = 0;
|
||||
|
||||
/* Initialize the NAND flash parameters */
|
||||
ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
|
||||
|
@ -1872,9 +1872,8 @@ static void switch_state(struct nandsim *ns)
|
|||
}
|
||||
}
|
||||
|
||||
static u_char ns_nand_read_byte(struct mtd_info *mtd)
|
||||
static u_char ns_nand_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nandsim *ns = nand_get_controller_data(chip);
|
||||
u_char outb = 0x00;
|
||||
|
||||
|
@ -1934,9 +1933,8 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
|
|||
return outb;
|
||||
}
|
||||
|
||||
static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
|
||||
static void ns_nand_write_byte(struct nand_chip *chip, u_char byte)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nandsim *ns = nand_get_controller_data(chip);
|
||||
|
||||
/* Sanity and correctness checks */
|
||||
|
@ -2089,9 +2087,8 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
|
|||
return;
|
||||
}
|
||||
|
||||
static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
|
||||
static void ns_hwcontrol(struct nand_chip *chip, int cmd, unsigned int bitmask)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nandsim *ns = nand_get_controller_data(chip);
|
||||
|
||||
ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
|
||||
|
@ -2099,27 +2096,18 @@ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
|
|||
ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
ns_nand_write_byte(mtd, cmd);
|
||||
ns_nand_write_byte(chip, cmd);
|
||||
}
|
||||
|
||||
static int ns_device_ready(struct mtd_info *mtd)
|
||||
static int ns_device_ready(struct nand_chip *chip)
|
||||
{
|
||||
NS_DBG("device_ready\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint16_t ns_nand_read_word(struct mtd_info *mtd)
|
||||
static void ns_nand_write_buf(struct nand_chip *chip, const u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
NS_DBG("read_word\n");
|
||||
|
||||
return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
|
||||
}
|
||||
|
||||
static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nandsim *ns = nand_get_controller_data(chip);
|
||||
|
||||
/* Check that chip is expecting data input */
|
||||
|
@ -2145,9 +2133,8 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
|||
}
|
||||
}
|
||||
|
||||
static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void ns_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct nandsim *ns = nand_get_controller_data(chip);
|
||||
|
||||
/* Sanity and correctness checks */
|
||||
|
@ -2169,7 +2156,7 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
|
||||
buf[i] = chip->legacy.read_byte(chip);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -2262,12 +2249,11 @@ static int __init ns_init_module(void)
|
|||
/*
|
||||
* Register simulator's callbacks.
|
||||
*/
|
||||
chip->cmd_ctrl = ns_hwcontrol;
|
||||
chip->read_byte = ns_nand_read_byte;
|
||||
chip->dev_ready = ns_device_ready;
|
||||
chip->write_buf = ns_nand_write_buf;
|
||||
chip->read_buf = ns_nand_read_buf;
|
||||
chip->read_word = ns_nand_read_word;
|
||||
chip->legacy.cmd_ctrl = ns_hwcontrol;
|
||||
chip->legacy.read_byte = ns_nand_read_byte;
|
||||
chip->legacy.dev_ready = ns_device_ready;
|
||||
chip->legacy.write_buf = ns_nand_write_buf;
|
||||
chip->legacy.read_buf = ns_nand_read_buf;
|
||||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
chip->ecc.algo = NAND_ECC_HAMMING;
|
||||
/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
|
||||
|
@ -2319,7 +2305,7 @@ static int __init ns_init_module(void)
|
|||
goto error;
|
||||
|
||||
chip->dummy_controller.ops = &ns_controller_ops;
|
||||
retval = nand_scan(nsmtd, 1);
|
||||
retval = nand_scan(chip, 1);
|
||||
if (retval) {
|
||||
NS_ERR("Could not scan NAND Simulator device\n");
|
||||
goto error;
|
||||
|
@ -2364,7 +2350,7 @@ static int __init ns_init_module(void)
|
|||
|
||||
err_exit:
|
||||
free_nandsim(nand);
|
||||
nand_release(nsmtd);
|
||||
nand_release(chip);
|
||||
for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
|
||||
kfree(nand->partitions[i].name);
|
||||
error:
|
||||
|
@ -2386,7 +2372,7 @@ static void __exit ns_cleanup_module(void)
|
|||
int i;
|
||||
|
||||
free_nandsim(ns); /* Free nandsim private resources */
|
||||
nand_release(nsmtd); /* Unregister driver */
|
||||
nand_release(chip); /* Unregister driver */
|
||||
for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
|
||||
kfree(ns->partitions[i].name);
|
||||
kfree(mtd_to_nand(nsmtd)); /* Free other structures */
|
||||
|
|
|
@ -44,10 +44,9 @@ struct ndfc_controller {
|
|||
|
||||
static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS];
|
||||
|
||||
static void ndfc_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void ndfc_select_chip(struct nand_chip *nchip, int chip)
|
||||
{
|
||||
uint32_t ccr;
|
||||
struct nand_chip *nchip = mtd_to_nand(mtd);
|
||||
struct ndfc_controller *ndfc = nand_get_controller_data(nchip);
|
||||
|
||||
ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
|
||||
|
@ -59,9 +58,8 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
|
|||
out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
|
||||
}
|
||||
|
||||
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
static void ndfc_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
|
@ -73,18 +71,16 @@ static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
|||
writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE);
|
||||
}
|
||||
|
||||
static int ndfc_ready(struct mtd_info *mtd)
|
||||
static int ndfc_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
|
||||
|
||||
return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
|
||||
}
|
||||
|
||||
static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
static void ndfc_enable_hwecc(struct nand_chip *chip, int mode)
|
||||
{
|
||||
uint32_t ccr;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
|
||||
|
||||
ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
|
||||
|
@ -93,10 +89,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
|
|||
wmb();
|
||||
}
|
||||
|
||||
static int ndfc_calculate_ecc(struct mtd_info *mtd,
|
||||
static int ndfc_calculate_ecc(struct nand_chip *chip,
|
||||
const u_char *dat, u_char *ecc_code)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
|
||||
uint32_t ecc;
|
||||
uint8_t *p = (uint8_t *)&ecc;
|
||||
|
@ -118,9 +113,8 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
|
|||
* functions. No further checking, as nand_base will always read/write
|
||||
* page aligned.
|
||||
*/
|
||||
static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void ndfc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
|
||||
uint32_t *p = (uint32_t *) buf;
|
||||
|
||||
|
@ -128,9 +122,8 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
|||
*p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
|
||||
}
|
||||
|
||||
static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
static void ndfc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct ndfc_controller *ndfc = nand_get_controller_data(chip);
|
||||
uint32_t *p = (uint32_t *) buf;
|
||||
|
||||
|
@ -149,15 +142,15 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
|
|||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
int ret;
|
||||
|
||||
chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
|
||||
chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
|
||||
chip->cmd_ctrl = ndfc_hwcontrol;
|
||||
chip->dev_ready = ndfc_ready;
|
||||
chip->legacy.IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
|
||||
chip->legacy.IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
|
||||
chip->legacy.cmd_ctrl = ndfc_hwcontrol;
|
||||
chip->legacy.dev_ready = ndfc_ready;
|
||||
chip->select_chip = ndfc_select_chip;
|
||||
chip->chip_delay = 50;
|
||||
chip->legacy.chip_delay = 50;
|
||||
chip->controller = &ndfc->ndfc_control;
|
||||
chip->read_buf = ndfc_read_buf;
|
||||
chip->write_buf = ndfc_write_buf;
|
||||
chip->legacy.read_buf = ndfc_read_buf;
|
||||
chip->legacy.write_buf = ndfc_write_buf;
|
||||
chip->ecc.correct = nand_correct_data;
|
||||
chip->ecc.hwctl = ndfc_enable_hwecc;
|
||||
chip->ecc.calculate = ndfc_calculate_ecc;
|
||||
|
@ -174,14 +167,14 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
|
|||
return -ENODEV;
|
||||
nand_set_flash_node(chip, flash_np);
|
||||
|
||||
mtd->name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev),
|
||||
flash_np->name);
|
||||
mtd->name = kasprintf(GFP_KERNEL, "%s.%pOFn", dev_name(&ndfc->ofdev->dev),
|
||||
flash_np);
|
||||
if (!mtd->name) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = nand_scan(mtd, 1);
|
||||
ret = nand_scan(chip, 1);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
@ -258,7 +251,7 @@ static int ndfc_remove(struct platform_device *ofdev)
|
|||
struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
|
||||
struct mtd_info *mtd = nand_to_mtd(&ndfc->chip);
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(&ndfc->chip);
|
||||
kfree(mtd->name);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -79,31 +79,31 @@ static const struct mtd_partition partitions[] = {
|
|||
}
|
||||
};
|
||||
|
||||
static unsigned char nuc900_nand_read_byte(struct mtd_info *mtd)
|
||||
static unsigned char nuc900_nand_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
unsigned char ret;
|
||||
struct nuc900_nand *nand = mtd_to_nuc900(mtd);
|
||||
struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
|
||||
|
||||
ret = (unsigned char)read_data_reg(nand);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void nuc900_nand_read_buf(struct mtd_info *mtd,
|
||||
static void nuc900_nand_read_buf(struct nand_chip *chip,
|
||||
unsigned char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nuc900_nand *nand = mtd_to_nuc900(mtd);
|
||||
struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = (unsigned char)read_data_reg(nand);
|
||||
}
|
||||
|
||||
static void nuc900_nand_write_buf(struct mtd_info *mtd,
|
||||
static void nuc900_nand_write_buf(struct nand_chip *chip,
|
||||
const unsigned char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nuc900_nand *nand = mtd_to_nuc900(mtd);
|
||||
struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
write_data_reg(nand, buf[i]);
|
||||
|
@ -120,19 +120,20 @@ static int nuc900_check_rb(struct nuc900_nand *nand)
|
|||
return val;
|
||||
}
|
||||
|
||||
static int nuc900_nand_devready(struct mtd_info *mtd)
|
||||
static int nuc900_nand_devready(struct nand_chip *chip)
|
||||
{
|
||||
struct nuc900_nand *nand = mtd_to_nuc900(mtd);
|
||||
struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
|
||||
int ready;
|
||||
|
||||
ready = (nuc900_check_rb(nand)) ? 1 : 0;
|
||||
return ready;
|
||||
}
|
||||
|
||||
static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
|
||||
static void nuc900_nand_command_lp(struct nand_chip *chip,
|
||||
unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
register struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct nuc900_nand *nand = mtd_to_nuc900(mtd);
|
||||
|
||||
if (command == NAND_CMD_READOOB) {
|
||||
|
@ -174,9 +175,9 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
|
|||
return;
|
||||
|
||||
case NAND_CMD_RESET:
|
||||
if (chip->dev_ready)
|
||||
if (chip->legacy.dev_ready)
|
||||
break;
|
||||
udelay(chip->chip_delay);
|
||||
udelay(chip->legacy.chip_delay);
|
||||
|
||||
write_cmd_reg(nand, NAND_CMD_STATUS);
|
||||
write_cmd_reg(nand, command);
|
||||
|
@ -195,8 +196,8 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
|
|||
write_cmd_reg(nand, NAND_CMD_READSTART);
|
||||
default:
|
||||
|
||||
if (!chip->dev_ready) {
|
||||
udelay(chip->chip_delay);
|
||||
if (!chip->legacy.dev_ready) {
|
||||
udelay(chip->legacy.chip_delay);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -205,7 +206,7 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
|
|||
* any case on any machine. */
|
||||
ndelay(100);
|
||||
|
||||
while (!chip->dev_ready(mtd))
|
||||
while (!chip->legacy.dev_ready(chip))
|
||||
;
|
||||
}
|
||||
|
||||
|
@ -253,12 +254,12 @@ static int nuc900_nand_probe(struct platform_device *pdev)
|
|||
return -ENOENT;
|
||||
clk_enable(nuc900_nand->clk);
|
||||
|
||||
chip->cmdfunc = nuc900_nand_command_lp;
|
||||
chip->dev_ready = nuc900_nand_devready;
|
||||
chip->read_byte = nuc900_nand_read_byte;
|
||||
chip->write_buf = nuc900_nand_write_buf;
|
||||
chip->read_buf = nuc900_nand_read_buf;
|
||||
chip->chip_delay = 50;
|
||||
chip->legacy.cmdfunc = nuc900_nand_command_lp;
|
||||
chip->legacy.dev_ready = nuc900_nand_devready;
|
||||
chip->legacy.read_byte = nuc900_nand_read_byte;
|
||||
chip->legacy.write_buf = nuc900_nand_write_buf;
|
||||
chip->legacy.read_buf = nuc900_nand_read_buf;
|
||||
chip->legacy.chip_delay = 50;
|
||||
chip->options = 0;
|
||||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
chip->ecc.algo = NAND_ECC_HAMMING;
|
||||
|
@ -270,7 +271,7 @@ static int nuc900_nand_probe(struct platform_device *pdev)
|
|||
|
||||
nuc900_nand_enable(nuc900_nand);
|
||||
|
||||
if (nand_scan(mtd, 1))
|
||||
if (nand_scan(chip, 1))
|
||||
return -ENXIO;
|
||||
|
||||
mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions));
|
||||
|
@ -284,7 +285,7 @@ static int nuc900_nand_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
|
||||
|
||||
nand_release(nand_to_mtd(&nuc900_nand->chip));
|
||||
nand_release(&nuc900_nand->chip);
|
||||
clk_disable(nuc900_nand->clk);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -240,7 +240,7 @@ static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
|
|||
|
||||
/**
|
||||
* omap_hwcontrol - hardware specific access to control-lines
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip object
|
||||
* @cmd: command to device
|
||||
* @ctrl:
|
||||
* NAND_NCE: bit 0 -> don't care
|
||||
|
@ -249,9 +249,9 @@ static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
|
|||
*
|
||||
* NOTE: boards may use different bits for these!!
|
||||
*/
|
||||
static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
static void omap_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
|
||||
|
||||
if (cmd != NAND_CMD_NONE) {
|
||||
if (ctrl & NAND_CLE)
|
||||
|
@ -275,7 +275,7 @@ static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
|
|||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
|
||||
ioread8_rep(nand->IO_ADDR_R, buf, len);
|
||||
ioread8_rep(nand->legacy.IO_ADDR_R, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -291,7 +291,7 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
|
|||
bool status;
|
||||
|
||||
while (len--) {
|
||||
iowrite8(*p++, info->nand.IO_ADDR_W);
|
||||
iowrite8(*p++, info->nand.legacy.IO_ADDR_W);
|
||||
/* wait until buffer is available for write */
|
||||
do {
|
||||
status = info->ops->nand_writebuffer_empty();
|
||||
|
@ -309,7 +309,7 @@ static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
|
|||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
|
||||
ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
|
||||
ioread16_rep(nand->legacy.IO_ADDR_R, buf, len / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -327,7 +327,7 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
|
|||
len >>= 1;
|
||||
|
||||
while (len--) {
|
||||
iowrite16(*p++, info->nand.IO_ADDR_W);
|
||||
iowrite16(*p++, info->nand.legacy.IO_ADDR_W);
|
||||
/* wait until buffer is available for write */
|
||||
do {
|
||||
status = info->ops->nand_writebuffer_empty();
|
||||
|
@ -337,12 +337,13 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
|
|||
|
||||
/**
|
||||
* omap_read_buf_pref - read data from NAND controller into buffer
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip object
|
||||
* @buf: buffer to store date
|
||||
* @len: number of bytes to read
|
||||
*/
|
||||
static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void omap_read_buf_pref(struct nand_chip *chip, u_char *buf, int len)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
uint32_t r_count = 0;
|
||||
int ret = 0;
|
||||
|
@ -372,7 +373,7 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
|
|||
r_count = readl(info->reg.gpmc_prefetch_status);
|
||||
r_count = PREFETCH_STATUS_FIFO_CNT(r_count);
|
||||
r_count = r_count >> 2;
|
||||
ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
|
||||
ioread32_rep(info->nand.legacy.IO_ADDR_R, p, r_count);
|
||||
p += r_count;
|
||||
len -= r_count << 2;
|
||||
} while (len);
|
||||
|
@ -383,13 +384,14 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
|
|||
|
||||
/**
|
||||
* omap_write_buf_pref - write buffer to NAND controller
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip object
|
||||
* @buf: data buffer
|
||||
* @len: number of bytes to write
|
||||
*/
|
||||
static void omap_write_buf_pref(struct mtd_info *mtd,
|
||||
const u_char *buf, int len)
|
||||
static void omap_write_buf_pref(struct nand_chip *chip, const u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
uint32_t w_count = 0;
|
||||
int i = 0, ret = 0;
|
||||
|
@ -399,7 +401,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
|
|||
|
||||
/* take care of subpage writes */
|
||||
if (len % 2 != 0) {
|
||||
writeb(*buf, info->nand.IO_ADDR_W);
|
||||
writeb(*buf, info->nand.legacy.IO_ADDR_W);
|
||||
p = (u16 *)(buf + 1);
|
||||
len--;
|
||||
}
|
||||
|
@ -419,7 +421,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
|
|||
w_count = PREFETCH_STATUS_FIFO_CNT(w_count);
|
||||
w_count = w_count >> 1;
|
||||
for (i = 0; (i < w_count) && len; i++, len -= 2)
|
||||
iowrite16(*p++, info->nand.IO_ADDR_W);
|
||||
iowrite16(*p++, info->nand.legacy.IO_ADDR_W);
|
||||
}
|
||||
/* wait for data to flushed-out before reset the prefetch */
|
||||
tim = 0;
|
||||
|
@ -528,14 +530,17 @@ out_copy:
|
|||
|
||||
/**
|
||||
* omap_read_buf_dma_pref - read data from NAND controller into buffer
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip object
|
||||
* @buf: buffer to store date
|
||||
* @len: number of bytes to read
|
||||
*/
|
||||
static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void omap_read_buf_dma_pref(struct nand_chip *chip, u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
if (len <= mtd->oobsize)
|
||||
omap_read_buf_pref(mtd, buf, len);
|
||||
omap_read_buf_pref(chip, buf, len);
|
||||
else
|
||||
/* start transfer in DMA mode */
|
||||
omap_nand_dma_transfer(mtd, buf, len, 0x0);
|
||||
|
@ -543,18 +548,20 @@ static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
|
|||
|
||||
/**
|
||||
* omap_write_buf_dma_pref - write buffer to NAND controller
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip object
|
||||
* @buf: data buffer
|
||||
* @len: number of bytes to write
|
||||
*/
|
||||
static void omap_write_buf_dma_pref(struct mtd_info *mtd,
|
||||
const u_char *buf, int len)
|
||||
static void omap_write_buf_dma_pref(struct nand_chip *chip, const u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
if (len <= mtd->oobsize)
|
||||
omap_write_buf_pref(mtd, buf, len);
|
||||
omap_write_buf_pref(chip, buf, len);
|
||||
else
|
||||
/* start transfer in DMA mode */
|
||||
omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
|
||||
omap_nand_dma_transfer(mtd, (u_char *)buf, len, 0x1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -578,14 +585,14 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
|
|||
bytes = info->buf_len;
|
||||
else if (!info->buf_len)
|
||||
bytes = 0;
|
||||
iowrite32_rep(info->nand.IO_ADDR_W,
|
||||
(u32 *)info->buf, bytes >> 2);
|
||||
iowrite32_rep(info->nand.legacy.IO_ADDR_W, (u32 *)info->buf,
|
||||
bytes >> 2);
|
||||
info->buf = info->buf + bytes;
|
||||
info->buf_len -= bytes;
|
||||
|
||||
} else {
|
||||
ioread32_rep(info->nand.IO_ADDR_R,
|
||||
(u32 *)info->buf, bytes >> 2);
|
||||
ioread32_rep(info->nand.legacy.IO_ADDR_R, (u32 *)info->buf,
|
||||
bytes >> 2);
|
||||
info->buf = info->buf + bytes;
|
||||
|
||||
if (this_irq == info->gpmc_irq_count)
|
||||
|
@ -605,17 +612,19 @@ done:
|
|||
|
||||
/*
|
||||
* omap_read_buf_irq_pref - read data from NAND controller into buffer
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip object
|
||||
* @buf: buffer to store date
|
||||
* @len: number of bytes to read
|
||||
*/
|
||||
static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void omap_read_buf_irq_pref(struct nand_chip *chip, u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
int ret = 0;
|
||||
|
||||
if (len <= mtd->oobsize) {
|
||||
omap_read_buf_pref(mtd, buf, len);
|
||||
omap_read_buf_pref(chip, buf, len);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -651,20 +660,21 @@ out_copy:
|
|||
|
||||
/*
|
||||
* omap_write_buf_irq_pref - write buffer to NAND controller
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip object
|
||||
* @buf: data buffer
|
||||
* @len: number of bytes to write
|
||||
*/
|
||||
static void omap_write_buf_irq_pref(struct mtd_info *mtd,
|
||||
const u_char *buf, int len)
|
||||
static void omap_write_buf_irq_pref(struct nand_chip *chip, const u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
int ret = 0;
|
||||
unsigned long tim, limit;
|
||||
u32 val;
|
||||
|
||||
if (len <= mtd->oobsize) {
|
||||
omap_write_buf_pref(mtd, buf, len);
|
||||
omap_write_buf_pref(chip, buf, len);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -857,7 +867,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
|
|||
|
||||
/**
|
||||
* omap_correct_data - Compares the ECC read with HW generated ECC
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip object
|
||||
* @dat: page data
|
||||
* @read_ecc: ecc read from nand flash
|
||||
* @calc_ecc: ecc read from HW ECC registers
|
||||
|
@ -869,10 +879,10 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
|
|||
* corrected errors is returned. If uncorrectable errors exist, %-1 is
|
||||
* returned.
|
||||
*/
|
||||
static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
static int omap_correct_data(struct nand_chip *chip, u_char *dat,
|
||||
u_char *read_ecc, u_char *calc_ecc)
|
||||
{
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
|
||||
int blockCnt = 0, i = 0, ret = 0;
|
||||
int stat = 0;
|
||||
|
||||
|
@ -900,7 +910,7 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
|
|||
|
||||
/**
|
||||
* omap_calcuate_ecc - Generate non-inverted ECC bytes.
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip object
|
||||
* @dat: The pointer to data on which ecc is computed
|
||||
* @ecc_code: The ecc_code buffer
|
||||
*
|
||||
|
@ -910,10 +920,10 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
|
|||
* an erased page will produce an ECC mismatch between generated and read
|
||||
* ECC bytes that has to be dealt with separately.
|
||||
*/
|
||||
static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
||||
static int omap_calculate_ecc(struct nand_chip *chip, const u_char *dat,
|
||||
u_char *ecc_code)
|
||||
{
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
|
||||
u32 val;
|
||||
|
||||
val = readl(info->reg.gpmc_ecc_config);
|
||||
|
@ -935,10 +945,9 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
|||
* @mtd: MTD device structure
|
||||
* @mode: Read/Write mode
|
||||
*/
|
||||
static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
static void omap_enable_hwecc(struct nand_chip *chip, int mode)
|
||||
{
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
|
||||
unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
|
||||
u32 val;
|
||||
|
||||
|
@ -972,8 +981,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
|
|||
|
||||
/**
|
||||
* omap_wait - wait until the command is done
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND Chip structure
|
||||
* @this: NAND Chip structure
|
||||
*
|
||||
* Wait function is called during Program and erase operations and
|
||||
* the way it is called from MTD layer, we should wait till the NAND
|
||||
|
@ -982,10 +990,9 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
|
|||
* Erase can take up to 400ms and program up to 20ms according to
|
||||
* general NAND and SmartMedia specs
|
||||
*/
|
||||
static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
static int omap_wait(struct nand_chip *this)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(this));
|
||||
unsigned long timeo = jiffies;
|
||||
int status, state = this->state;
|
||||
|
||||
|
@ -1012,9 +1019,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
|||
*
|
||||
* Returns true if ready and false if busy.
|
||||
*/
|
||||
static int omap_dev_ready(struct mtd_info *mtd)
|
||||
static int omap_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
|
||||
|
||||
return gpiod_get_value(info->ready_gpiod);
|
||||
}
|
||||
|
@ -1030,13 +1037,13 @@ static int omap_dev_ready(struct mtd_info *mtd)
|
|||
* eccsize0 = 0 (no additional protected byte in spare area)
|
||||
* eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
|
||||
*/
|
||||
static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
|
||||
static void __maybe_unused omap_enable_hwecc_bch(struct nand_chip *chip,
|
||||
int mode)
|
||||
{
|
||||
unsigned int bch_type;
|
||||
unsigned int dev_width, nsectors;
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
|
||||
enum omap_ecc ecc_opt = info->ecc_opt;
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u32 val, wr_mode;
|
||||
unsigned int ecc_size1, ecc_size0;
|
||||
|
||||
|
@ -1256,7 +1263,7 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
|
|||
|
||||
/**
|
||||
* omap_calculate_ecc_bch_sw - ECC generator for sector for SW based correction
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip object
|
||||
* @dat: The pointer to data on which ecc is computed
|
||||
* @ecc_code: The ecc_code buffer
|
||||
*
|
||||
|
@ -1264,10 +1271,10 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd,
|
|||
* when SW based correction is required as ECC is required for one sector
|
||||
* at a time.
|
||||
*/
|
||||
static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd,
|
||||
static int omap_calculate_ecc_bch_sw(struct nand_chip *chip,
|
||||
const u_char *dat, u_char *ecc_calc)
|
||||
{
|
||||
return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0);
|
||||
return _omap_calculate_ecc_bch(nand_to_mtd(chip), dat, ecc_calc, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1339,7 +1346,7 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
|
|||
|
||||
/**
|
||||
* omap_elm_correct_data - corrects page data area in case error reported
|
||||
* @mtd: MTD device structure
|
||||
* @chip: NAND chip object
|
||||
* @data: page data
|
||||
* @read_ecc: ecc read from nand flash
|
||||
* @calc_ecc: ecc read from HW ECC registers
|
||||
|
@ -1348,10 +1355,10 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
|
|||
* In case of non-zero ecc vector, first filter out erased-pages, and
|
||||
* then process data via ELM to detect bit-flips.
|
||||
*/
|
||||
static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
||||
static int omap_elm_correct_data(struct nand_chip *chip, u_char *data,
|
||||
u_char *read_ecc, u_char *calc_ecc)
|
||||
{
|
||||
struct omap_nand_info *info = mtd_to_omap(mtd);
|
||||
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
|
||||
struct nand_ecc_ctrl *ecc = &info->nand.ecc;
|
||||
int eccsteps = info->nand.ecc.steps;
|
||||
int i , j, stat = 0;
|
||||
|
@ -1512,7 +1519,6 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
|||
|
||||
/**
|
||||
* omap_write_page_bch - BCH ecc based write page function for entire page
|
||||
* @mtd: mtd info structure
|
||||
* @chip: nand chip info structure
|
||||
* @buf: data buffer
|
||||
* @oob_required: must write chip->oob_poi to OOB
|
||||
|
@ -1520,19 +1526,20 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
|||
*
|
||||
* Custom write page method evolved to support multi sector writing in one shot
|
||||
*/
|
||||
static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
static int omap_write_page_bch(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
int ret;
|
||||
uint8_t *ecc_calc = chip->ecc.calc_buf;
|
||||
|
||||
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
|
||||
|
||||
/* Enable GPMC ecc engine */
|
||||
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
|
||||
chip->ecc.hwctl(chip, NAND_ECC_WRITE);
|
||||
|
||||
/* Write data */
|
||||
chip->write_buf(mtd, buf, mtd->writesize);
|
||||
chip->legacy.write_buf(chip, buf, mtd->writesize);
|
||||
|
||||
/* Update ecc vector from GPMC result registers */
|
||||
omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]);
|
||||
|
@ -1543,14 +1550,13 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return ret;
|
||||
|
||||
/* Write ecc vector to OOB area */
|
||||
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap_write_subpage_bch - BCH hardware ECC based subpage write
|
||||
* @mtd: mtd info structure
|
||||
* @chip: nand chip info structure
|
||||
* @offset: column address of subpage within the page
|
||||
* @data_len: data length
|
||||
|
@ -1560,11 +1566,11 @@ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
*
|
||||
* OMAP optimized subpage write method.
|
||||
*/
|
||||
static int omap_write_subpage_bch(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u32 offset,
|
||||
static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset,
|
||||
u32 data_len, const u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
u8 *ecc_calc = chip->ecc.calc_buf;
|
||||
int ecc_size = chip->ecc.size;
|
||||
int ecc_bytes = chip->ecc.bytes;
|
||||
|
@ -1582,10 +1588,10 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
|
|||
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
|
||||
|
||||
/* Enable GPMC ECC engine */
|
||||
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
|
||||
chip->ecc.hwctl(chip, NAND_ECC_WRITE);
|
||||
|
||||
/* Write data */
|
||||
chip->write_buf(mtd, buf, mtd->writesize);
|
||||
chip->legacy.write_buf(chip, buf, mtd->writesize);
|
||||
|
||||
for (step = 0; step < ecc_steps; step++) {
|
||||
/* mask ECC of un-touched subpages by padding 0xFF */
|
||||
|
@ -1610,14 +1616,13 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
|
|||
return ret;
|
||||
|
||||
/* write OOB buffer to NAND device */
|
||||
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
|
||||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap_read_page_bch - BCH ecc based page read function for entire page
|
||||
* @mtd: mtd info structure
|
||||
* @chip: nand chip info structure
|
||||
* @buf: buffer to store read data
|
||||
* @oob_required: caller requires OOB data read to chip->oob_poi
|
||||
|
@ -1630,9 +1635,10 @@ static int omap_write_subpage_bch(struct mtd_info *mtd,
|
|||
* ecc engine enabled. ecc vector updated after read of OOB data.
|
||||
* For non error pages ecc vector reported as zero.
|
||||
*/
|
||||
static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int omap_read_page_bch(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
uint8_t *ecc_calc = chip->ecc.calc_buf;
|
||||
uint8_t *ecc_code = chip->ecc.code_buf;
|
||||
int stat, ret;
|
||||
|
@ -1641,10 +1647,10 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
nand_read_page_op(chip, page, 0, NULL, 0);
|
||||
|
||||
/* Enable GPMC ecc engine */
|
||||
chip->ecc.hwctl(mtd, NAND_ECC_READ);
|
||||
chip->ecc.hwctl(chip, NAND_ECC_READ);
|
||||
|
||||
/* Read data */
|
||||
chip->read_buf(mtd, buf, mtd->writesize);
|
||||
chip->legacy.read_buf(chip, buf, mtd->writesize);
|
||||
|
||||
/* Read oob bytes */
|
||||
nand_change_read_column_op(chip,
|
||||
|
@ -1660,7 +1666,7 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc);
|
||||
stat = chip->ecc.correct(chip, buf, ecc_code, ecc_calc);
|
||||
|
||||
if (stat < 0) {
|
||||
mtd->ecc_stats.failed++;
|
||||
|
@ -1927,8 +1933,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
|
|||
/* Re-populate low-level callbacks based on xfer modes */
|
||||
switch (info->xfer_type) {
|
||||
case NAND_OMAP_PREFETCH_POLLED:
|
||||
chip->read_buf = omap_read_buf_pref;
|
||||
chip->write_buf = omap_write_buf_pref;
|
||||
chip->legacy.read_buf = omap_read_buf_pref;
|
||||
chip->legacy.write_buf = omap_write_buf_pref;
|
||||
break;
|
||||
|
||||
case NAND_OMAP_POLLED:
|
||||
|
@ -1960,8 +1966,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
|
|||
err);
|
||||
return err;
|
||||
}
|
||||
chip->read_buf = omap_read_buf_dma_pref;
|
||||
chip->write_buf = omap_write_buf_dma_pref;
|
||||
chip->legacy.read_buf = omap_read_buf_dma_pref;
|
||||
chip->legacy.write_buf = omap_write_buf_dma_pref;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1996,8 +2002,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
|
|||
return err;
|
||||
}
|
||||
|
||||
chip->read_buf = omap_read_buf_irq_pref;
|
||||
chip->write_buf = omap_write_buf_irq_pref;
|
||||
chip->legacy.read_buf = omap_read_buf_irq_pref;
|
||||
chip->legacy.write_buf = omap_write_buf_irq_pref;
|
||||
|
||||
break;
|
||||
|
||||
|
@ -2215,16 +2221,16 @@ static int omap_nand_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(nand_chip->IO_ADDR_R))
|
||||
return PTR_ERR(nand_chip->IO_ADDR_R);
|
||||
nand_chip->legacy.IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(nand_chip->legacy.IO_ADDR_R))
|
||||
return PTR_ERR(nand_chip->legacy.IO_ADDR_R);
|
||||
|
||||
info->phys_base = res->start;
|
||||
|
||||
nand_chip->controller = &omap_gpmc_controller;
|
||||
|
||||
nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
|
||||
nand_chip->cmd_ctrl = omap_hwcontrol;
|
||||
nand_chip->legacy.IO_ADDR_W = nand_chip->legacy.IO_ADDR_R;
|
||||
nand_chip->legacy.cmd_ctrl = omap_hwcontrol;
|
||||
|
||||
info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
|
||||
GPIOD_IN);
|
||||
|
@ -2241,11 +2247,11 @@ static int omap_nand_probe(struct platform_device *pdev)
|
|||
* device and read status register until you get a failure or success
|
||||
*/
|
||||
if (info->ready_gpiod) {
|
||||
nand_chip->dev_ready = omap_dev_ready;
|
||||
nand_chip->chip_delay = 0;
|
||||
nand_chip->legacy.dev_ready = omap_dev_ready;
|
||||
nand_chip->legacy.chip_delay = 0;
|
||||
} else {
|
||||
nand_chip->waitfunc = omap_wait;
|
||||
nand_chip->chip_delay = 50;
|
||||
nand_chip->legacy.waitfunc = omap_wait;
|
||||
nand_chip->legacy.chip_delay = 50;
|
||||
}
|
||||
|
||||
if (info->flash_bbt)
|
||||
|
@ -2254,7 +2260,7 @@ static int omap_nand_probe(struct platform_device *pdev)
|
|||
/* scan NAND device connected to chip controller */
|
||||
nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;
|
||||
|
||||
err = nand_scan(mtd, 1);
|
||||
err = nand_scan(nand_chip, 1);
|
||||
if (err)
|
||||
goto return_error;
|
||||
|
||||
|
@ -2290,7 +2296,7 @@ static int omap_nand_remove(struct platform_device *pdev)
|
|||
}
|
||||
if (info->dma)
|
||||
dma_release_channel(info->dma);
|
||||
nand_release(mtd);
|
||||
nand_release(nand_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,9 +26,9 @@ struct orion_nand_info {
|
|||
struct clk *clk;
|
||||
};
|
||||
|
||||
static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
static void orion_nand_cmd_ctrl(struct nand_chip *nc, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *nc = mtd_to_nand(mtd);
|
||||
struct orion_nand_data *board = nand_get_controller_data(nc);
|
||||
u32 offs;
|
||||
|
||||
|
@ -45,13 +45,12 @@ static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl
|
|||
if (nc->options & NAND_BUSWIDTH_16)
|
||||
offs <<= 1;
|
||||
|
||||
writeb(cmd, nc->IO_ADDR_W + offs);
|
||||
writeb(cmd, nc->legacy.IO_ADDR_W + offs);
|
||||
}
|
||||
|
||||
static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void orion_nand_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
void __iomem *io_base = chip->IO_ADDR_R;
|
||||
void __iomem *io_base = chip->legacy.IO_ADDR_R;
|
||||
#if defined(__LINUX_ARM_ARCH__) && __LINUX_ARM_ARCH__ >= 5
|
||||
uint64_t *buf64;
|
||||
#endif
|
||||
|
@ -137,14 +136,14 @@ static int __init orion_nand_probe(struct platform_device *pdev)
|
|||
|
||||
nand_set_controller_data(nc, board);
|
||||
nand_set_flash_node(nc, pdev->dev.of_node);
|
||||
nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
|
||||
nc->cmd_ctrl = orion_nand_cmd_ctrl;
|
||||
nc->read_buf = orion_nand_read_buf;
|
||||
nc->legacy.IO_ADDR_R = nc->legacy.IO_ADDR_W = io_base;
|
||||
nc->legacy.cmd_ctrl = orion_nand_cmd_ctrl;
|
||||
nc->legacy.read_buf = orion_nand_read_buf;
|
||||
nc->ecc.mode = NAND_ECC_SOFT;
|
||||
nc->ecc.algo = NAND_ECC_HAMMING;
|
||||
|
||||
if (board->chip_delay)
|
||||
nc->chip_delay = board->chip_delay;
|
||||
nc->legacy.chip_delay = board->chip_delay;
|
||||
|
||||
WARN(board->width > 16,
|
||||
"%d bit bus width out of range",
|
||||
|
@ -174,14 +173,14 @@ static int __init orion_nand_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = nand_scan(mtd, 1);
|
||||
ret = nand_scan(nc, 1);
|
||||
if (ret)
|
||||
goto no_dev;
|
||||
|
||||
mtd->name = "orion_nand";
|
||||
ret = mtd_device_register(mtd, board->parts, board->nr_parts);
|
||||
if (ret) {
|
||||
nand_release(mtd);
|
||||
nand_release(nc);
|
||||
goto no_dev;
|
||||
}
|
||||
|
||||
|
@ -196,9 +195,8 @@ static int orion_nand_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct orion_nand_info *info = platform_get_drvdata(pdev);
|
||||
struct nand_chip *chip = &info->chip;
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(chip);
|
||||
|
||||
clk_disable_unprepare(info->clk);
|
||||
|
||||
|
|
|
@ -38,35 +38,32 @@ struct oxnas_nand_ctrl {
|
|||
struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
|
||||
};
|
||||
|
||||
static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t oxnas_nand_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
|
||||
|
||||
return readb(oxnas->io_base);
|
||||
}
|
||||
|
||||
static void oxnas_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
||||
static void oxnas_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
|
||||
|
||||
ioread8_rep(oxnas->io_base, buf, len);
|
||||
}
|
||||
|
||||
static void oxnas_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
||||
static void oxnas_nand_write_buf(struct nand_chip *chip, const u8 *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
|
||||
|
||||
iowrite8_rep(oxnas->io_base, buf, len);
|
||||
}
|
||||
|
||||
/* Single CS command control */
|
||||
static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
static void oxnas_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
|
||||
|
||||
if (ctrl & NAND_CLE)
|
||||
|
@ -135,20 +132,20 @@ static int oxnas_nand_probe(struct platform_device *pdev)
|
|||
mtd->dev.parent = &pdev->dev;
|
||||
mtd->priv = chip;
|
||||
|
||||
chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
|
||||
chip->read_buf = oxnas_nand_read_buf;
|
||||
chip->read_byte = oxnas_nand_read_byte;
|
||||
chip->write_buf = oxnas_nand_write_buf;
|
||||
chip->chip_delay = 30;
|
||||
chip->legacy.cmd_ctrl = oxnas_nand_cmd_ctrl;
|
||||
chip->legacy.read_buf = oxnas_nand_read_buf;
|
||||
chip->legacy.read_byte = oxnas_nand_read_byte;
|
||||
chip->legacy.write_buf = oxnas_nand_write_buf;
|
||||
chip->legacy.chip_delay = 30;
|
||||
|
||||
/* Scan to find existence of the device */
|
||||
err = nand_scan(mtd, 1);
|
||||
err = nand_scan(chip, 1);
|
||||
if (err)
|
||||
goto err_clk_unprepare;
|
||||
|
||||
err = mtd_device_register(mtd, NULL, 0);
|
||||
if (err) {
|
||||
nand_release(mtd);
|
||||
nand_release(chip);
|
||||
goto err_clk_unprepare;
|
||||
}
|
||||
|
||||
|
@ -176,7 +173,7 @@ static int oxnas_nand_remove(struct platform_device *pdev)
|
|||
struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
|
||||
|
||||
if (oxnas->chips[0])
|
||||
nand_release(nand_to_mtd(oxnas->chips[0]));
|
||||
nand_release(oxnas->chips[0]);
|
||||
|
||||
clk_disable_unprepare(oxnas->clk);
|
||||
|
||||
|
|
|
@ -43,49 +43,44 @@ static unsigned int lpcctl;
|
|||
static struct mtd_info *pasemi_nand_mtd;
|
||||
static const char driver_name[] = "pasemi-nand";
|
||||
|
||||
static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void pasemi_read_buf(struct nand_chip *chip, u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
while (len > 0x800) {
|
||||
memcpy_fromio(buf, chip->IO_ADDR_R, 0x800);
|
||||
memcpy_fromio(buf, chip->legacy.IO_ADDR_R, 0x800);
|
||||
buf += 0x800;
|
||||
len -= 0x800;
|
||||
}
|
||||
memcpy_fromio(buf, chip->IO_ADDR_R, len);
|
||||
memcpy_fromio(buf, chip->legacy.IO_ADDR_R, len);
|
||||
}
|
||||
|
||||
static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
static void pasemi_write_buf(struct nand_chip *chip, const u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
while (len > 0x800) {
|
||||
memcpy_toio(chip->IO_ADDR_R, buf, 0x800);
|
||||
memcpy_toio(chip->legacy.IO_ADDR_R, buf, 0x800);
|
||||
buf += 0x800;
|
||||
len -= 0x800;
|
||||
}
|
||||
memcpy_toio(chip->IO_ADDR_R, buf, len);
|
||||
memcpy_toio(chip->legacy.IO_ADDR_R, buf, len);
|
||||
}
|
||||
|
||||
static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
return;
|
||||
|
||||
if (ctrl & NAND_CLE)
|
||||
out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
|
||||
out_8(chip->legacy.IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
|
||||
else
|
||||
out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
|
||||
out_8(chip->legacy.IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
|
||||
|
||||
/* Push out posted writes */
|
||||
eieio();
|
||||
inl(lpcctl);
|
||||
}
|
||||
|
||||
int pasemi_device_ready(struct mtd_info *mtd)
|
||||
int pasemi_device_ready(struct nand_chip *chip)
|
||||
{
|
||||
return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
|
||||
}
|
||||
|
@ -122,10 +117,10 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
|
|||
/* Link the private data with the MTD structure */
|
||||
pasemi_nand_mtd->dev.parent = dev;
|
||||
|
||||
chip->IO_ADDR_R = of_iomap(np, 0);
|
||||
chip->IO_ADDR_W = chip->IO_ADDR_R;
|
||||
chip->legacy.IO_ADDR_R = of_iomap(np, 0);
|
||||
chip->legacy.IO_ADDR_W = chip->legacy.IO_ADDR_R;
|
||||
|
||||
if (!chip->IO_ADDR_R) {
|
||||
if (!chip->legacy.IO_ADDR_R) {
|
||||
err = -EIO;
|
||||
goto out_mtd;
|
||||
}
|
||||
|
@ -144,11 +139,11 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
|
|||
goto out_ior;
|
||||
}
|
||||
|
||||
chip->cmd_ctrl = pasemi_hwcontrol;
|
||||
chip->dev_ready = pasemi_device_ready;
|
||||
chip->read_buf = pasemi_read_buf;
|
||||
chip->write_buf = pasemi_write_buf;
|
||||
chip->chip_delay = 0;
|
||||
chip->legacy.cmd_ctrl = pasemi_hwcontrol;
|
||||
chip->legacy.dev_ready = pasemi_device_ready;
|
||||
chip->legacy.read_buf = pasemi_read_buf;
|
||||
chip->legacy.write_buf = pasemi_write_buf;
|
||||
chip->legacy.chip_delay = 0;
|
||||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
chip->ecc.algo = NAND_ECC_HAMMING;
|
||||
|
||||
|
@ -156,7 +151,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
|
|||
chip->bbt_options = NAND_BBT_USE_FLASH;
|
||||
|
||||
/* Scan to find existence of the device */
|
||||
err = nand_scan(pasemi_nand_mtd, 1);
|
||||
err = nand_scan(chip, 1);
|
||||
if (err)
|
||||
goto out_lpc;
|
||||
|
||||
|
@ -174,7 +169,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
|
|||
out_lpc:
|
||||
release_region(lpcctl, 4);
|
||||
out_ior:
|
||||
iounmap(chip->IO_ADDR_R);
|
||||
iounmap(chip->legacy.IO_ADDR_R);
|
||||
out_mtd:
|
||||
kfree(chip);
|
||||
out:
|
||||
|
@ -191,11 +186,11 @@ static int pasemi_nand_remove(struct platform_device *ofdev)
|
|||
chip = mtd_to_nand(pasemi_nand_mtd);
|
||||
|
||||
/* Release resources, unregister device */
|
||||
nand_release(pasemi_nand_mtd);
|
||||
nand_release(chip);
|
||||
|
||||
release_region(lpcctl, 4);
|
||||
|
||||
iounmap(chip->IO_ADDR_R);
|
||||
iounmap(chip->legacy.IO_ADDR_R);
|
||||
|
||||
/* Free the MTD device structure */
|
||||
kfree(chip);
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
|
||||
struct plat_nand_data {
|
||||
struct nand_chip chip;
|
||||
|
@ -60,14 +59,14 @@ static int plat_nand_probe(struct platform_device *pdev)
|
|||
mtd = nand_to_mtd(&data->chip);
|
||||
mtd->dev.parent = &pdev->dev;
|
||||
|
||||
data->chip.IO_ADDR_R = data->io_base;
|
||||
data->chip.IO_ADDR_W = data->io_base;
|
||||
data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
|
||||
data->chip.dev_ready = pdata->ctrl.dev_ready;
|
||||
data->chip.legacy.IO_ADDR_R = data->io_base;
|
||||
data->chip.legacy.IO_ADDR_W = data->io_base;
|
||||
data->chip.legacy.cmd_ctrl = pdata->ctrl.cmd_ctrl;
|
||||
data->chip.legacy.dev_ready = pdata->ctrl.dev_ready;
|
||||
data->chip.select_chip = pdata->ctrl.select_chip;
|
||||
data->chip.write_buf = pdata->ctrl.write_buf;
|
||||
data->chip.read_buf = pdata->ctrl.read_buf;
|
||||
data->chip.chip_delay = pdata->chip.chip_delay;
|
||||
data->chip.legacy.write_buf = pdata->ctrl.write_buf;
|
||||
data->chip.legacy.read_buf = pdata->ctrl.read_buf;
|
||||
data->chip.legacy.chip_delay = pdata->chip.chip_delay;
|
||||
data->chip.options |= pdata->chip.options;
|
||||
data->chip.bbt_options |= pdata->chip.bbt_options;
|
||||
|
||||
|
@ -84,7 +83,7 @@ static int plat_nand_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* Scan to find existence of the device */
|
||||
err = nand_scan(mtd, pdata->chip.nr_chips);
|
||||
err = nand_scan(&data->chip, pdata->chip.nr_chips);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -97,7 +96,7 @@ static int plat_nand_probe(struct platform_device *pdev)
|
|||
if (!err)
|
||||
return err;
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(&data->chip);
|
||||
out:
|
||||
if (pdata->ctrl.remove)
|
||||
pdata->ctrl.remove(pdev);
|
||||
|
@ -112,7 +111,7 @@ static int plat_nand_remove(struct platform_device *pdev)
|
|||
struct plat_nand_data *data = platform_get_drvdata(pdev);
|
||||
struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
nand_release(nand_to_mtd(&data->chip));
|
||||
nand_release(&data->chip);
|
||||
if (pdata->ctrl.remove)
|
||||
pdata->ctrl.remove(pdev);
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma/qcom_bam_dma.h>
|
||||
#include <linux/dma-direct.h> /* XXX: drivers shall never use this directly! */
|
||||
|
||||
/* NANDc reg offsets */
|
||||
#define NAND_FLASH_CMD 0x00
|
||||
|
@ -350,7 +349,8 @@ struct nandc_regs {
|
|||
* @data_buffer: our local DMA buffer for page read/writes,
|
||||
* used when we can't use the buffer provided
|
||||
* by upper layers directly
|
||||
* @buf_size/count/start: markers for chip->read_buf/write_buf functions
|
||||
* @buf_size/count/start: markers for chip->legacy.read_buf/write_buf
|
||||
* functions
|
||||
* @reg_read_buf: local buffer for reading back registers via DMA
|
||||
* @reg_read_dma: contains dma address for register read buffer
|
||||
* @reg_read_pos: marker for data read in reg_read_buf
|
||||
|
@ -1155,8 +1155,8 @@ static void config_nand_cw_write(struct qcom_nand_controller *nandc)
|
|||
}
|
||||
|
||||
/*
|
||||
* the following functions are used within chip->cmdfunc() to perform different
|
||||
* NAND_CMD_* commands
|
||||
* the following functions are used within chip->legacy.cmdfunc() to
|
||||
* perform different NAND_CMD_* commands
|
||||
*/
|
||||
|
||||
/* sets up descriptors for NAND_CMD_PARAM */
|
||||
|
@ -1436,15 +1436,14 @@ static void post_command(struct qcom_nand_host *host, int command)
|
|||
}
|
||||
|
||||
/*
|
||||
* Implements chip->cmdfunc. It's only used for a limited set of commands.
|
||||
* The rest of the commands wouldn't be called by upper layers. For example,
|
||||
* NAND_CMD_READOOB would never be called because we have our own versions
|
||||
* of read_oob ops for nand_ecc_ctrl.
|
||||
* Implements chip->legacy.cmdfunc. It's only used for a limited set of
|
||||
* commands. The rest of the commands wouldn't be called by upper layers.
|
||||
* For example, NAND_CMD_READOOB would never be called because we have our own
|
||||
* versions of read_oob ops for nand_ecc_ctrl.
|
||||
*/
|
||||
static void qcom_nandc_command(struct mtd_info *mtd, unsigned int command,
|
||||
static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct qcom_nand_host *host = to_qcom_nand_host(chip);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||
|
@ -1949,8 +1948,8 @@ static int copy_last_cw(struct qcom_nand_host *host, int page)
|
|||
}
|
||||
|
||||
/* implements ecc->read_page() */
|
||||
static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct qcom_nand_host *host = to_qcom_nand_host(chip);
|
||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||
|
@ -1966,10 +1965,10 @@ static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
}
|
||||
|
||||
/* implements ecc->read_page_raw() */
|
||||
static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t *buf,
|
||||
static int qcom_nandc_read_page_raw(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct qcom_nand_host *host = to_qcom_nand_host(chip);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
int cw, ret;
|
||||
|
@ -1989,8 +1988,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd,
|
|||
}
|
||||
|
||||
/* implements ecc->read_oob() */
|
||||
static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int qcom_nandc_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct qcom_nand_host *host = to_qcom_nand_host(chip);
|
||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||
|
@ -2007,8 +2005,8 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
}
|
||||
|
||||
/* implements ecc->write_page() */
|
||||
static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required, int page)
|
||||
static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct qcom_nand_host *host = to_qcom_nand_host(chip);
|
||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||
|
@ -2077,10 +2075,11 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
}
|
||||
|
||||
/* implements ecc->write_page_raw() */
|
||||
static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
static int qcom_nandc_write_page_raw(struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct qcom_nand_host *host = to_qcom_nand_host(chip);
|
||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
|
@ -2155,9 +2154,9 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd,
|
|||
* since ECC is calculated for the combined codeword. So update the OOB from
|
||||
* chip->oob_poi, and pad the data area with OxFF before writing.
|
||||
*/
|
||||
static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int qcom_nandc_write_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct qcom_nand_host *host = to_qcom_nand_host(chip);
|
||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
|
@ -2197,9 +2196,9 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs)
|
||||
static int qcom_nandc_block_bad(struct nand_chip *chip, loff_t ofs)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct qcom_nand_host *host = to_qcom_nand_host(chip);
|
||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
|
@ -2235,9 +2234,8 @@ err:
|
|||
return bad;
|
||||
}
|
||||
|
||||
static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct qcom_nand_host *host = to_qcom_nand_host(chip);
|
||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
|
@ -2278,14 +2276,13 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||
}
|
||||
|
||||
/*
|
||||
* the three functions below implement chip->read_byte(), chip->read_buf()
|
||||
* and chip->write_buf() respectively. these aren't used for
|
||||
* reading/writing page data, they are used for smaller data like reading
|
||||
* id, status etc
|
||||
* the three functions below implement chip->legacy.read_byte(),
|
||||
* chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
|
||||
* aren't used for reading/writing page data, they are used for smaller data
|
||||
* like reading id, status etc
|
||||
*/
|
||||
static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct qcom_nand_host *host = to_qcom_nand_host(chip);
|
||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||
u8 *buf = nandc->data_buffer;
|
||||
|
@ -2305,9 +2302,8 @@ static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||
int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
|
||||
|
||||
|
@ -2315,10 +2311,9 @@ static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
|||
nandc->buf_start += real_len;
|
||||
}
|
||||
|
||||
static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
|
||||
static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||
int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
|
||||
|
||||
|
@ -2328,9 +2323,8 @@ static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
|
|||
}
|
||||
|
||||
/* we support only one external chip for now */
|
||||
static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr)
|
||||
static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
|
||||
|
||||
if (chipnr <= 0)
|
||||
|
@ -2809,13 +2803,13 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
|
|||
mtd->owner = THIS_MODULE;
|
||||
mtd->dev.parent = dev;
|
||||
|
||||
chip->cmdfunc = qcom_nandc_command;
|
||||
chip->legacy.cmdfunc = qcom_nandc_command;
|
||||
chip->select_chip = qcom_nandc_select_chip;
|
||||
chip->read_byte = qcom_nandc_read_byte;
|
||||
chip->read_buf = qcom_nandc_read_buf;
|
||||
chip->write_buf = qcom_nandc_write_buf;
|
||||
chip->set_features = nand_get_set_features_notsupp;
|
||||
chip->get_features = nand_get_set_features_notsupp;
|
||||
chip->legacy.read_byte = qcom_nandc_read_byte;
|
||||
chip->legacy.read_buf = qcom_nandc_read_buf;
|
||||
chip->legacy.write_buf = qcom_nandc_write_buf;
|
||||
chip->legacy.set_features = nand_get_set_features_notsupp;
|
||||
chip->legacy.get_features = nand_get_set_features_notsupp;
|
||||
|
||||
/*
|
||||
* the bad block marker is readable only when we read the last codeword
|
||||
|
@ -2825,8 +2819,8 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
|
|||
* and block_markbad helpers until we permanently switch to using
|
||||
* MTD_OPS_RAW for all drivers (with the help of badblockbits)
|
||||
*/
|
||||
chip->block_bad = qcom_nandc_block_bad;
|
||||
chip->block_markbad = qcom_nandc_block_markbad;
|
||||
chip->legacy.block_bad = qcom_nandc_block_bad;
|
||||
chip->legacy.block_markbad = qcom_nandc_block_markbad;
|
||||
|
||||
chip->controller = &nandc->controller;
|
||||
chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER |
|
||||
|
@ -2835,7 +2829,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
|
|||
/* set up initial status value */
|
||||
host->status = NAND_STATUS_READY | NAND_STATUS_WP;
|
||||
|
||||
ret = nand_scan(mtd, 1);
|
||||
ret = nand_scan(chip, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -3000,7 +2994,7 @@ static int qcom_nandc_remove(struct platform_device *pdev)
|
|||
struct qcom_nand_host *host;
|
||||
|
||||
list_for_each_entry(host, &nandc->host_list, node)
|
||||
nand_release(nand_to_mtd(&host->chip));
|
||||
nand_release(&host->chip);
|
||||
|
||||
|
||||
qcom_nandc_unalloc(nandc);
|
||||
|
|
|
@ -232,9 +232,9 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read)
|
|||
/*
|
||||
* Program data lines of the nand chip to send data to it
|
||||
*/
|
||||
static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
static void r852_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
|
||||
{
|
||||
struct r852_device *dev = r852_get_dev(mtd);
|
||||
struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
|
||||
uint32_t reg;
|
||||
|
||||
/* Don't allow any access to hardware if we suspect card removal */
|
||||
|
@ -266,9 +266,9 @@ static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
|||
/*
|
||||
* Read data lines of the nand chip to retrieve data
|
||||
*/
|
||||
static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void r852_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
struct r852_device *dev = r852_get_dev(mtd);
|
||||
struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
|
||||
uint32_t reg;
|
||||
|
||||
if (dev->card_unstable) {
|
||||
|
@ -303,9 +303,9 @@ static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
|||
/*
|
||||
* Read one byte from nand chip
|
||||
*/
|
||||
static uint8_t r852_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t r852_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct r852_device *dev = r852_get_dev(mtd);
|
||||
struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
|
||||
|
||||
/* Same problem as in r852_read_buf.... */
|
||||
if (dev->card_unstable)
|
||||
|
@ -317,9 +317,9 @@ static uint8_t r852_read_byte(struct mtd_info *mtd)
|
|||
/*
|
||||
* Control several chip lines & send commands
|
||||
*/
|
||||
static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
|
||||
static void r852_cmdctl(struct nand_chip *chip, int dat, unsigned int ctrl)
|
||||
{
|
||||
struct r852_device *dev = r852_get_dev(mtd);
|
||||
struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
|
||||
|
||||
if (dev->card_unstable)
|
||||
return;
|
||||
|
@ -362,7 +362,7 @@ static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
|
|||
* Wait till card is ready.
|
||||
* based on nand_wait, but returns errors on DMA error
|
||||
*/
|
||||
static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
static int r852_wait(struct nand_chip *chip)
|
||||
{
|
||||
struct r852_device *dev = nand_get_controller_data(chip);
|
||||
|
||||
|
@ -373,7 +373,7 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
|||
msecs_to_jiffies(400) : msecs_to_jiffies(20));
|
||||
|
||||
while (time_before(jiffies, timeout))
|
||||
if (chip->dev_ready(mtd))
|
||||
if (chip->legacy.dev_ready(chip))
|
||||
break;
|
||||
|
||||
nand_status_op(chip, &status);
|
||||
|
@ -390,9 +390,9 @@ static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
|||
* Check if card is ready
|
||||
*/
|
||||
|
||||
static int r852_ready(struct mtd_info *mtd)
|
||||
static int r852_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct r852_device *dev = r852_get_dev(mtd);
|
||||
struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
|
||||
return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY);
|
||||
}
|
||||
|
||||
|
@ -401,9 +401,9 @@ static int r852_ready(struct mtd_info *mtd)
|
|||
* Set ECC engine mode
|
||||
*/
|
||||
|
||||
static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
|
||||
static void r852_ecc_hwctl(struct nand_chip *chip, int mode)
|
||||
{
|
||||
struct r852_device *dev = r852_get_dev(mtd);
|
||||
struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
|
||||
|
||||
if (dev->card_unstable)
|
||||
return;
|
||||
|
@ -433,10 +433,10 @@ static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
|
|||
* Calculate ECC, only used for writes
|
||||
*/
|
||||
|
||||
static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
|
||||
static int r852_ecc_calculate(struct nand_chip *chip, const uint8_t *dat,
|
||||
uint8_t *ecc_code)
|
||||
{
|
||||
struct r852_device *dev = r852_get_dev(mtd);
|
||||
struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
|
||||
struct sm_oob *oob = (struct sm_oob *)ecc_code;
|
||||
uint32_t ecc1, ecc2;
|
||||
|
||||
|
@ -465,14 +465,14 @@ static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
|
|||
* Correct the data using ECC, hw did almost everything for us
|
||||
*/
|
||||
|
||||
static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
|
||||
static int r852_ecc_correct(struct nand_chip *chip, uint8_t *dat,
|
||||
uint8_t *read_ecc, uint8_t *calc_ecc)
|
||||
{
|
||||
uint32_t ecc_reg;
|
||||
uint8_t ecc_status, err_byte;
|
||||
int i, error = 0;
|
||||
|
||||
struct r852_device *dev = r852_get_dev(mtd);
|
||||
struct r852_device *dev = r852_get_dev(nand_to_mtd(chip));
|
||||
|
||||
if (dev->card_unstable)
|
||||
return 0;
|
||||
|
@ -521,9 +521,10 @@ exit:
|
|||
* This is copy of nand_read_oob_std
|
||||
* nand_read_oob_syndrome assumes we can send column address - we can't
|
||||
*/
|
||||
static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int r852_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
return nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
|
||||
}
|
||||
|
||||
|
@ -636,7 +637,7 @@ static int r852_register_nand_device(struct r852_device *dev)
|
|||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(dev->chip);
|
||||
|
||||
WARN_ON(dev->card_registred);
|
||||
WARN_ON(dev->card_registered);
|
||||
|
||||
mtd->dev.parent = &dev->pci_dev->dev;
|
||||
|
||||
|
@ -653,10 +654,10 @@ static int r852_register_nand_device(struct r852_device *dev)
|
|||
goto error3;
|
||||
}
|
||||
|
||||
dev->card_registred = 1;
|
||||
dev->card_registered = 1;
|
||||
return 0;
|
||||
error3:
|
||||
nand_release(mtd);
|
||||
nand_release(dev->chip);
|
||||
error1:
|
||||
/* Force card redetect */
|
||||
dev->card_detected = 0;
|
||||
|
@ -671,13 +672,13 @@ static void r852_unregister_nand_device(struct r852_device *dev)
|
|||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(dev->chip);
|
||||
|
||||
if (!dev->card_registred)
|
||||
if (!dev->card_registered)
|
||||
return;
|
||||
|
||||
device_remove_file(&mtd->dev, &dev_attr_media_type);
|
||||
nand_release(mtd);
|
||||
nand_release(dev->chip);
|
||||
r852_engine_disable(dev);
|
||||
dev->card_registred = 0;
|
||||
dev->card_registered = 0;
|
||||
}
|
||||
|
||||
/* Card state updater */
|
||||
|
@ -691,7 +692,7 @@ static void r852_card_detect_work(struct work_struct *work)
|
|||
dev->card_unstable = 0;
|
||||
|
||||
/* False alarm */
|
||||
if (dev->card_detected == dev->card_registred)
|
||||
if (dev->card_detected == dev->card_registered)
|
||||
goto exit;
|
||||
|
||||
/* Read media properties */
|
||||
|
@ -852,14 +853,14 @@ static int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
|
|||
goto error4;
|
||||
|
||||
/* commands */
|
||||
chip->cmd_ctrl = r852_cmdctl;
|
||||
chip->waitfunc = r852_wait;
|
||||
chip->dev_ready = r852_ready;
|
||||
chip->legacy.cmd_ctrl = r852_cmdctl;
|
||||
chip->legacy.waitfunc = r852_wait;
|
||||
chip->legacy.dev_ready = r852_ready;
|
||||
|
||||
/* I/O */
|
||||
chip->read_byte = r852_read_byte;
|
||||
chip->read_buf = r852_read_buf;
|
||||
chip->write_buf = r852_write_buf;
|
||||
chip->legacy.read_byte = r852_read_byte;
|
||||
chip->legacy.read_buf = r852_read_buf;
|
||||
chip->legacy.write_buf = r852_write_buf;
|
||||
|
||||
/* ecc */
|
||||
chip->ecc.mode = NAND_ECC_HW_SYNDROME;
|
||||
|
@ -1025,7 +1026,6 @@ static int r852_suspend(struct device *device)
|
|||
static int r852_resume(struct device *device)
|
||||
{
|
||||
struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
|
||||
struct mtd_info *mtd = nand_to_mtd(dev->chip);
|
||||
|
||||
r852_disable_irqs(dev);
|
||||
r852_card_update_present(dev);
|
||||
|
@ -1033,7 +1033,7 @@ static int r852_resume(struct device *device)
|
|||
|
||||
|
||||
/* If card status changed, just do the work */
|
||||
if (dev->card_detected != dev->card_registred) {
|
||||
if (dev->card_detected != dev->card_registered) {
|
||||
dbg("card was %s during low power state",
|
||||
dev->card_detected ? "added" : "removed");
|
||||
|
||||
|
@ -1043,11 +1043,11 @@ static int r852_resume(struct device *device)
|
|||
}
|
||||
|
||||
/* Otherwise, initialize the card */
|
||||
if (dev->card_registred) {
|
||||
if (dev->card_registered) {
|
||||
r852_engine_enable(dev);
|
||||
dev->chip->select_chip(mtd, 0);
|
||||
dev->chip->select_chip(dev->chip, 0);
|
||||
nand_reset_op(dev->chip);
|
||||
dev->chip->select_chip(mtd, -1);
|
||||
dev->chip->select_chip(dev->chip, -1);
|
||||
}
|
||||
|
||||
/* Program card detection IRQ */
|
||||
|
|
|
@ -129,7 +129,7 @@ struct r852_device {
|
|||
/* card status area */
|
||||
struct delayed_work card_detect_work;
|
||||
struct workqueue_struct *card_workqueue;
|
||||
int card_registred; /* card registered with mtd */
|
||||
int card_registered; /* card registered with mtd */
|
||||
int card_detected; /* card detected in slot */
|
||||
int card_unstable; /* whenever the card is inserted,
|
||||
is not known yet */
|
||||
|
|
|
@ -404,7 +404,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
|
|||
|
||||
/**
|
||||
* s3c2410_nand_select_chip - select the given nand chip
|
||||
* @mtd: The MTD instance for this chip.
|
||||
* @this: NAND chip object.
|
||||
* @chip: The chip number.
|
||||
*
|
||||
* This is called by the MTD layer to either select a given chip for the
|
||||
|
@ -415,11 +415,10 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info)
|
|||
* platform specific selection code is called to route nFCE to the specific
|
||||
* chip.
|
||||
*/
|
||||
static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void s3c2410_nand_select_chip(struct nand_chip *this, int chip)
|
||||
{
|
||||
struct s3c2410_nand_info *info;
|
||||
struct s3c2410_nand_mtd *nmtd;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
unsigned long cur;
|
||||
|
||||
nmtd = nand_get_controller_data(this);
|
||||
|
@ -457,9 +456,10 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
|
|||
* Issue command and address cycles to the chip
|
||||
*/
|
||||
|
||||
static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
static void s3c2410_nand_hwcontrol(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
|
@ -473,9 +473,10 @@ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
|
|||
|
||||
/* command and control functions */
|
||||
|
||||
static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
static void s3c2440_nand_hwcontrol(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
|
@ -492,29 +493,33 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
|
|||
* returns 0 if the nand is busy, 1 if it is ready
|
||||
*/
|
||||
|
||||
static int s3c2410_nand_devready(struct mtd_info *mtd)
|
||||
static int s3c2410_nand_devready(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
|
||||
}
|
||||
|
||||
static int s3c2440_nand_devready(struct mtd_info *mtd)
|
||||
static int s3c2440_nand_devready(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
|
||||
}
|
||||
|
||||
static int s3c2412_nand_devready(struct mtd_info *mtd)
|
||||
static int s3c2412_nand_devready(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
|
||||
}
|
||||
|
||||
/* ECC handling functions */
|
||||
|
||||
static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||
static int s3c2410_nand_correct_data(struct nand_chip *chip, u_char *dat,
|
||||
u_char *read_ecc, u_char *calc_ecc)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
unsigned int diff0, diff1, diff2;
|
||||
unsigned int bit, byte;
|
||||
|
@ -591,38 +596,42 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
|||
* generator block to ECC the data as it passes through]
|
||||
*/
|
||||
|
||||
static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
static void s3c2410_nand_enable_hwecc(struct nand_chip *chip, int mode)
|
||||
{
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
struct s3c2410_nand_info *info;
|
||||
unsigned long ctrl;
|
||||
|
||||
info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
|
||||
ctrl = readl(info->regs + S3C2410_NFCONF);
|
||||
ctrl |= S3C2410_NFCONF_INITECC;
|
||||
writel(ctrl, info->regs + S3C2410_NFCONF);
|
||||
}
|
||||
|
||||
static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
static void s3c2412_nand_enable_hwecc(struct nand_chip *chip, int mode)
|
||||
{
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
struct s3c2410_nand_info *info;
|
||||
unsigned long ctrl;
|
||||
|
||||
info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
|
||||
ctrl = readl(info->regs + S3C2440_NFCONT);
|
||||
writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC,
|
||||
info->regs + S3C2440_NFCONT);
|
||||
}
|
||||
|
||||
static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
static void s3c2440_nand_enable_hwecc(struct nand_chip *chip, int mode)
|
||||
{
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
struct s3c2410_nand_info *info;
|
||||
unsigned long ctrl;
|
||||
|
||||
info = s3c2410_nand_mtd_toinfo(nand_to_mtd(chip));
|
||||
ctrl = readl(info->regs + S3C2440_NFCONT);
|
||||
writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
|
||||
}
|
||||
|
||||
static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
||||
u_char *ecc_code)
|
||||
static int s3c2410_nand_calculate_ecc(struct nand_chip *chip,
|
||||
const u_char *dat, u_char *ecc_code)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
|
||||
ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
|
||||
|
@ -634,9 +643,10 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
||||
u_char *ecc_code)
|
||||
static int s3c2412_nand_calculate_ecc(struct nand_chip *chip,
|
||||
const u_char *dat, u_char *ecc_code)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
|
||||
|
||||
|
@ -649,9 +659,10 @@ static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
||||
u_char *ecc_code)
|
||||
static int s3c2440_nand_calculate_ecc(struct nand_chip *chip,
|
||||
const u_char *dat, u_char *ecc_code)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
|
||||
|
||||
|
@ -668,14 +679,14 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
|||
* use read/write block to move the data buffers to/from the controller
|
||||
*/
|
||||
|
||||
static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void s3c2410_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
readsb(this->IO_ADDR_R, buf, len);
|
||||
readsb(this->legacy.IO_ADDR_R, buf, len);
|
||||
}
|
||||
|
||||
static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void s3c2440_nand_read_buf(struct nand_chip *this, u_char *buf, int len)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(this);
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
|
||||
readsl(info->regs + S3C2440_NFDATA, buf, len >> 2);
|
||||
|
@ -689,16 +700,16 @@ static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
|||
}
|
||||
}
|
||||
|
||||
static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
|
||||
static void s3c2410_nand_write_buf(struct nand_chip *this, const u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
writesb(this->IO_ADDR_W, buf, len);
|
||||
writesb(this->legacy.IO_ADDR_W, buf, len);
|
||||
}
|
||||
|
||||
static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
|
||||
static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf,
|
||||
int len)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(this);
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
|
||||
writesl(info->regs + S3C2440_NFDATA, buf, len >> 2);
|
||||
|
@ -781,7 +792,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
|
|||
|
||||
for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
|
||||
pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
|
||||
nand_release(nand_to_mtd(&ptr->chip));
|
||||
nand_release(&ptr->chip);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -809,9 +820,10 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, int csline,
|
||||
static int s3c2410_nand_setup_data_interface(struct nand_chip *chip, int csline,
|
||||
const struct nand_data_interface *conf)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
|
||||
struct s3c2410_platform_nand *pdata = info->platform;
|
||||
const struct nand_sdr_timings *timings;
|
||||
|
@ -852,10 +864,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
|
|||
|
||||
nand_set_flash_node(chip, set->of_node);
|
||||
|
||||
chip->write_buf = s3c2410_nand_write_buf;
|
||||
chip->read_buf = s3c2410_nand_read_buf;
|
||||
chip->legacy.write_buf = s3c2410_nand_write_buf;
|
||||
chip->legacy.read_buf = s3c2410_nand_read_buf;
|
||||
chip->select_chip = s3c2410_nand_select_chip;
|
||||
chip->chip_delay = 50;
|
||||
chip->legacy.chip_delay = 50;
|
||||
nand_set_controller_data(chip, nmtd);
|
||||
chip->options = set->options;
|
||||
chip->controller = &info->controller;
|
||||
|
@ -869,29 +881,29 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
|
|||
|
||||
switch (info->cpu_type) {
|
||||
case TYPE_S3C2410:
|
||||
chip->IO_ADDR_W = regs + S3C2410_NFDATA;
|
||||
chip->legacy.IO_ADDR_W = regs + S3C2410_NFDATA;
|
||||
info->sel_reg = regs + S3C2410_NFCONF;
|
||||
info->sel_bit = S3C2410_NFCONF_nFCE;
|
||||
chip->cmd_ctrl = s3c2410_nand_hwcontrol;
|
||||
chip->dev_ready = s3c2410_nand_devready;
|
||||
chip->legacy.cmd_ctrl = s3c2410_nand_hwcontrol;
|
||||
chip->legacy.dev_ready = s3c2410_nand_devready;
|
||||
break;
|
||||
|
||||
case TYPE_S3C2440:
|
||||
chip->IO_ADDR_W = regs + S3C2440_NFDATA;
|
||||
chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
|
||||
info->sel_reg = regs + S3C2440_NFCONT;
|
||||
info->sel_bit = S3C2440_NFCONT_nFCE;
|
||||
chip->cmd_ctrl = s3c2440_nand_hwcontrol;
|
||||
chip->dev_ready = s3c2440_nand_devready;
|
||||
chip->read_buf = s3c2440_nand_read_buf;
|
||||
chip->write_buf = s3c2440_nand_write_buf;
|
||||
chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol;
|
||||
chip->legacy.dev_ready = s3c2440_nand_devready;
|
||||
chip->legacy.read_buf = s3c2440_nand_read_buf;
|
||||
chip->legacy.write_buf = s3c2440_nand_write_buf;
|
||||
break;
|
||||
|
||||
case TYPE_S3C2412:
|
||||
chip->IO_ADDR_W = regs + S3C2440_NFDATA;
|
||||
chip->legacy.IO_ADDR_W = regs + S3C2440_NFDATA;
|
||||
info->sel_reg = regs + S3C2440_NFCONT;
|
||||
info->sel_bit = S3C2412_NFCONT_nFCE0;
|
||||
chip->cmd_ctrl = s3c2440_nand_hwcontrol;
|
||||
chip->dev_ready = s3c2412_nand_devready;
|
||||
chip->legacy.cmd_ctrl = s3c2440_nand_hwcontrol;
|
||||
chip->legacy.dev_ready = s3c2412_nand_devready;
|
||||
|
||||
if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
|
||||
dev_info(info->device, "System booted from NAND\n");
|
||||
|
@ -899,7 +911,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
|
|||
break;
|
||||
}
|
||||
|
||||
chip->IO_ADDR_R = chip->IO_ADDR_W;
|
||||
chip->legacy.IO_ADDR_R = chip->legacy.IO_ADDR_W;
|
||||
|
||||
nmtd->info = info;
|
||||
nmtd->set = set;
|
||||
|
@ -1170,7 +1182,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
|
|||
mtd->dev.parent = &pdev->dev;
|
||||
s3c2410_nand_init_chip(info, nmtd, sets);
|
||||
|
||||
err = nand_scan(mtd, sets ? sets->nr_chips : 1);
|
||||
err = nand_scan(&nmtd->chip, sets ? sets->nr_chips : 1);
|
||||
if (err)
|
||||
goto exit_error;
|
||||
|
||||
|
|
|
@ -480,7 +480,7 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
|
|||
|
||||
/* initiate DMA transfer */
|
||||
if (flctl->chan_fifo0_rx && rlen >= 32 &&
|
||||
flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
|
||||
flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_FROM_DEVICE) > 0)
|
||||
goto convert; /* DMA success */
|
||||
|
||||
/* do polling transfer */
|
||||
|
@ -539,7 +539,7 @@ static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
|
|||
|
||||
/* initiate DMA transfer */
|
||||
if (flctl->chan_fifo0_tx && rlen >= 32 &&
|
||||
flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
|
||||
flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_TO_DEVICE) > 0)
|
||||
return; /* DMA success */
|
||||
|
||||
/* do polling transfer */
|
||||
|
@ -611,21 +611,24 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
|
|||
writel(flcmcdr_val, FLCMCDR(flctl));
|
||||
}
|
||||
|
||||
static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
uint8_t *buf, int oob_required, int page)
|
||||
static int flctl_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
nand_read_page_op(chip, page, 0, buf, mtd->writesize);
|
||||
if (oob_required)
|
||||
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
static int flctl_write_page_hwecc(struct nand_chip *chip, const uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
|
||||
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||
chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
|
||||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
|
@ -747,9 +750,10 @@ static void execmd_write_oob(struct mtd_info *mtd)
|
|||
}
|
||||
}
|
||||
|
||||
static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
||||
static void flctl_cmdfunc(struct nand_chip *chip, unsigned int command,
|
||||
int column, int page_addr)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
||||
uint32_t read_cmd = 0;
|
||||
|
||||
|
@ -923,9 +927,9 @@ runtime_exit:
|
|||
return;
|
||||
}
|
||||
|
||||
static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
|
||||
static void flctl_select_chip(struct nand_chip *chip, int chipnr)
|
||||
{
|
||||
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
||||
struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
|
||||
int ret;
|
||||
|
||||
switch (chipnr) {
|
||||
|
@ -967,17 +971,17 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
|
|||
}
|
||||
}
|
||||
|
||||
static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
static void flctl_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
|
||||
{
|
||||
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
||||
struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
|
||||
|
||||
memcpy(&flctl->done_buff[flctl->index], buf, len);
|
||||
flctl->index += len;
|
||||
}
|
||||
|
||||
static uint8_t flctl_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t flctl_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
||||
struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
|
||||
uint8_t data;
|
||||
|
||||
data = flctl->done_buff[flctl->index];
|
||||
|
@ -985,18 +989,9 @@ static uint8_t flctl_read_byte(struct mtd_info *mtd)
|
|||
return data;
|
||||
}
|
||||
|
||||
static uint16_t flctl_read_word(struct mtd_info *mtd)
|
||||
static void flctl_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
|
||||
{
|
||||
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
||||
uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];
|
||||
|
||||
flctl->index += 2;
|
||||
return *buf;
|
||||
}
|
||||
|
||||
static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
{
|
||||
struct sh_flctl *flctl = mtd_to_flctl(mtd);
|
||||
struct sh_flctl *flctl = mtd_to_flctl(nand_to_mtd(chip));
|
||||
|
||||
memcpy(buf, &flctl->done_buff[flctl->index], len);
|
||||
flctl->index += len;
|
||||
|
@ -1183,16 +1178,15 @@ static int flctl_probe(struct platform_device *pdev)
|
|||
|
||||
/* Set address of hardware control function */
|
||||
/* 20 us command delay time */
|
||||
nand->chip_delay = 20;
|
||||
nand->legacy.chip_delay = 20;
|
||||
|
||||
nand->read_byte = flctl_read_byte;
|
||||
nand->read_word = flctl_read_word;
|
||||
nand->write_buf = flctl_write_buf;
|
||||
nand->read_buf = flctl_read_buf;
|
||||
nand->legacy.read_byte = flctl_read_byte;
|
||||
nand->legacy.write_buf = flctl_write_buf;
|
||||
nand->legacy.read_buf = flctl_read_buf;
|
||||
nand->select_chip = flctl_select_chip;
|
||||
nand->cmdfunc = flctl_cmdfunc;
|
||||
nand->set_features = nand_get_set_features_notsupp;
|
||||
nand->get_features = nand_get_set_features_notsupp;
|
||||
nand->legacy.cmdfunc = flctl_cmdfunc;
|
||||
nand->legacy.set_features = nand_get_set_features_notsupp;
|
||||
nand->legacy.get_features = nand_get_set_features_notsupp;
|
||||
|
||||
if (pdata->flcmncr_val & SEL_16BIT)
|
||||
nand->options |= NAND_BUSWIDTH_16;
|
||||
|
@ -1203,7 +1197,7 @@ static int flctl_probe(struct platform_device *pdev)
|
|||
flctl_setup_dma(flctl);
|
||||
|
||||
nand->dummy_controller.ops = &flctl_nand_controller_ops;
|
||||
ret = nand_scan(flctl_mtd, 1);
|
||||
ret = nand_scan(nand, 1);
|
||||
if (ret)
|
||||
goto err_chip;
|
||||
|
||||
|
@ -1226,7 +1220,7 @@ static int flctl_remove(struct platform_device *pdev)
|
|||
struct sh_flctl *flctl = platform_get_drvdata(pdev);
|
||||
|
||||
flctl_release_dma(flctl);
|
||||
nand_release(nand_to_mtd(&flctl->chip));
|
||||
nand_release(&flctl->chip);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -59,11 +59,10 @@ static inline struct sharpsl_nand *mtd_to_sharpsl(struct mtd_info *mtd)
|
|||
* NAND_ALE: bit 2 -> bit 2
|
||||
*
|
||||
*/
|
||||
static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
static void sharpsl_nand_hwcontrol(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
unsigned char bits = ctrl & 0x07;
|
||||
|
@ -76,24 +75,25 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
|
|||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
writeb(cmd, chip->IO_ADDR_W);
|
||||
writeb(cmd, chip->legacy.IO_ADDR_W);
|
||||
}
|
||||
|
||||
static int sharpsl_nand_dev_ready(struct mtd_info *mtd)
|
||||
static int sharpsl_nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
|
||||
struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
|
||||
return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0);
|
||||
}
|
||||
|
||||
static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
static void sharpsl_nand_enable_hwecc(struct nand_chip *chip, int mode)
|
||||
{
|
||||
struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
|
||||
struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
|
||||
writeb(0, sharpsl->io + ECCCLRR);
|
||||
}
|
||||
|
||||
static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
|
||||
static int sharpsl_nand_calculate_ecc(struct nand_chip *chip,
|
||||
const u_char * dat, u_char * ecc_code)
|
||||
{
|
||||
struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
|
||||
struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
|
||||
ecc_code[0] = ~readb(sharpsl->io + ECCLPUB);
|
||||
ecc_code[1] = ~readb(sharpsl->io + ECCLPLB);
|
||||
ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03;
|
||||
|
@ -153,13 +153,13 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
|
|||
writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL);
|
||||
|
||||
/* Set address of NAND IO lines */
|
||||
this->IO_ADDR_R = sharpsl->io + FLASHIO;
|
||||
this->IO_ADDR_W = sharpsl->io + FLASHIO;
|
||||
this->legacy.IO_ADDR_R = sharpsl->io + FLASHIO;
|
||||
this->legacy.IO_ADDR_W = sharpsl->io + FLASHIO;
|
||||
/* Set address of hardware control function */
|
||||
this->cmd_ctrl = sharpsl_nand_hwcontrol;
|
||||
this->dev_ready = sharpsl_nand_dev_ready;
|
||||
this->legacy.cmd_ctrl = sharpsl_nand_hwcontrol;
|
||||
this->legacy.dev_ready = sharpsl_nand_dev_ready;
|
||||
/* 15 us command delay time */
|
||||
this->chip_delay = 15;
|
||||
this->legacy.chip_delay = 15;
|
||||
/* set eccmode using hardware ECC */
|
||||
this->ecc.mode = NAND_ECC_HW;
|
||||
this->ecc.size = 256;
|
||||
|
@ -171,7 +171,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
|
|||
this->ecc.correct = nand_correct_data;
|
||||
|
||||
/* Scan to find existence of the device */
|
||||
err = nand_scan(mtd, 1);
|
||||
err = nand_scan(this, 1);
|
||||
if (err)
|
||||
goto err_scan;
|
||||
|
||||
|
@ -187,7 +187,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
err_add:
|
||||
nand_release(mtd);
|
||||
nand_release(this);
|
||||
|
||||
err_scan:
|
||||
iounmap(sharpsl->io);
|
||||
|
@ -205,7 +205,7 @@ static int sharpsl_nand_remove(struct platform_device *pdev)
|
|||
struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
|
||||
|
||||
/* Release resources, unregister device */
|
||||
nand_release(nand_to_mtd(&sharpsl->chip));
|
||||
nand_release(&sharpsl->chip);
|
||||
|
||||
iounmap(sharpsl->io);
|
||||
|
||||
|
|
|
@ -99,8 +99,9 @@ static const struct mtd_ooblayout_ops oob_sm_small_ops = {
|
|||
.free = oob_sm_small_ooblayout_free,
|
||||
};
|
||||
|
||||
static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
static int sm_block_markbad(struct nand_chip *chip, loff_t ofs)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct mtd_oob_ops ops;
|
||||
struct sm_oob oob;
|
||||
int ret;
|
||||
|
@ -167,7 +168,7 @@ static int sm_attach_chip(struct nand_chip *chip)
|
|||
/* Bad block marker position */
|
||||
chip->badblockpos = 0x05;
|
||||
chip->badblockbits = 7;
|
||||
chip->block_markbad = sm_block_markbad;
|
||||
chip->legacy.block_markbad = sm_block_markbad;
|
||||
|
||||
/* ECC layout */
|
||||
if (mtd->writesize == SM_SECTOR_SIZE)
|
||||
|
@ -195,7 +196,7 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia)
|
|||
/* Scan for card properties */
|
||||
chip->dummy_controller.ops = &sm_controller_ops;
|
||||
flash_ids = smartmedia ? nand_smartmedia_flash_ids : nand_xd_flash_ids;
|
||||
ret = nand_scan_with_ids(mtd, 1, flash_ids);
|
||||
ret = nand_scan_with_ids(chip, 1, flash_ids);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -34,15 +34,14 @@ struct socrates_nand_host {
|
|||
|
||||
/**
|
||||
* socrates_nand_write_buf - write buffer to chip
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
* @buf: data buffer
|
||||
* @len: number of bytes to write
|
||||
*/
|
||||
static void socrates_nand_write_buf(struct mtd_info *mtd,
|
||||
const uint8_t *buf, int len)
|
||||
static void socrates_nand_write_buf(struct nand_chip *this, const uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct socrates_nand_host *host = nand_get_controller_data(this);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
|
@ -54,14 +53,14 @@ static void socrates_nand_write_buf(struct mtd_info *mtd,
|
|||
|
||||
/**
|
||||
* socrates_nand_read_buf - read chip data into buffer
|
||||
* @mtd: MTD device structure
|
||||
* @this: NAND chip object
|
||||
* @buf: buffer to store date
|
||||
* @len: number of bytes to read
|
||||
*/
|
||||
static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void socrates_nand_read_buf(struct nand_chip *this, uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd_to_nand(mtd);
|
||||
struct socrates_nand_host *host = nand_get_controller_data(this);
|
||||
uint32_t val;
|
||||
|
||||
|
@ -78,31 +77,19 @@ static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
|||
* socrates_nand_read_byte - read one byte from the chip
|
||||
* @mtd: MTD device structure
|
||||
*/
|
||||
static uint8_t socrates_nand_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t socrates_nand_read_byte(struct nand_chip *this)
|
||||
{
|
||||
uint8_t byte;
|
||||
socrates_nand_read_buf(mtd, &byte, sizeof(byte));
|
||||
socrates_nand_read_buf(this, &byte, sizeof(byte));
|
||||
return byte;
|
||||
}
|
||||
|
||||
/**
|
||||
* socrates_nand_read_word - read one word from the chip
|
||||
* @mtd: MTD device structure
|
||||
*/
|
||||
static uint16_t socrates_nand_read_word(struct mtd_info *mtd)
|
||||
{
|
||||
uint16_t word;
|
||||
socrates_nand_read_buf(mtd, (uint8_t *)&word, sizeof(word));
|
||||
return word;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hardware specific access to control-lines
|
||||
*/
|
||||
static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
static void socrates_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
uint32_t val;
|
||||
|
||||
|
@ -125,9 +112,8 @@ static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
|||
/*
|
||||
* Read the Device Ready pin.
|
||||
*/
|
||||
static int socrates_nand_device_ready(struct mtd_info *mtd)
|
||||
static int socrates_nand_device_ready(struct nand_chip *nand_chip)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd_to_nand(mtd);
|
||||
struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
|
||||
|
||||
if (in_be32(host->io_base) & FPGA_NAND_BUSY)
|
||||
|
@ -166,26 +152,21 @@ static int socrates_nand_probe(struct platform_device *ofdev)
|
|||
mtd->name = "socrates_nand";
|
||||
mtd->dev.parent = &ofdev->dev;
|
||||
|
||||
/*should never be accessed directly */
|
||||
nand_chip->IO_ADDR_R = (void *)0xdeadbeef;
|
||||
nand_chip->IO_ADDR_W = (void *)0xdeadbeef;
|
||||
|
||||
nand_chip->cmd_ctrl = socrates_nand_cmd_ctrl;
|
||||
nand_chip->read_byte = socrates_nand_read_byte;
|
||||
nand_chip->read_word = socrates_nand_read_word;
|
||||
nand_chip->write_buf = socrates_nand_write_buf;
|
||||
nand_chip->read_buf = socrates_nand_read_buf;
|
||||
nand_chip->dev_ready = socrates_nand_device_ready;
|
||||
nand_chip->legacy.cmd_ctrl = socrates_nand_cmd_ctrl;
|
||||
nand_chip->legacy.read_byte = socrates_nand_read_byte;
|
||||
nand_chip->legacy.write_buf = socrates_nand_write_buf;
|
||||
nand_chip->legacy.read_buf = socrates_nand_read_buf;
|
||||
nand_chip->legacy.dev_ready = socrates_nand_device_ready;
|
||||
|
||||
nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
|
||||
nand_chip->ecc.algo = NAND_ECC_HAMMING;
|
||||
|
||||
/* TODO: I have no idea what real delay is. */
|
||||
nand_chip->chip_delay = 20; /* 20us command delay time */
|
||||
nand_chip->legacy.chip_delay = 20; /* 20us command delay time */
|
||||
|
||||
dev_set_drvdata(&ofdev->dev, host);
|
||||
|
||||
res = nand_scan(mtd, 1);
|
||||
res = nand_scan(nand_chip, 1);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
|
@ -193,7 +174,7 @@ static int socrates_nand_probe(struct platform_device *ofdev)
|
|||
if (!res)
|
||||
return res;
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(nand_chip);
|
||||
|
||||
out:
|
||||
iounmap(host->io_base);
|
||||
|
@ -206,9 +187,8 @@ out:
|
|||
static int socrates_nand_remove(struct platform_device *ofdev)
|
||||
{
|
||||
struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
|
||||
struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(&host->nand_chip);
|
||||
|
||||
iounmap(host->io_base);
|
||||
|
||||
|
|
|
@ -400,9 +400,8 @@ static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd,
|
|||
nfc->regs + NFC_REG_CTL);
|
||||
}
|
||||
|
||||
static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
|
||||
static int sunxi_nfc_dev_ready(struct nand_chip *nand)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
|
||||
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
|
||||
u32 mask;
|
||||
|
@ -420,9 +419,9 @@ static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
|
|||
return !!(readl(nfc->regs + NFC_REG_ST) & mask);
|
||||
}
|
||||
|
||||
static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
|
||||
static void sunxi_nfc_select_chip(struct nand_chip *nand, int chip)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct mtd_info *mtd = nand_to_mtd(nand);
|
||||
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
|
||||
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
|
||||
struct sunxi_nand_chip_sel *sel;
|
||||
|
@ -443,9 +442,9 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
|
|||
ctl |= NFC_CE_SEL(sel->cs) | NFC_EN |
|
||||
NFC_PAGE_SHIFT(nand->page_shift);
|
||||
if (sel->rb < 0) {
|
||||
nand->dev_ready = NULL;
|
||||
nand->legacy.dev_ready = NULL;
|
||||
} else {
|
||||
nand->dev_ready = sunxi_nfc_dev_ready;
|
||||
nand->legacy.dev_ready = sunxi_nfc_dev_ready;
|
||||
ctl |= NFC_RB_SEL(sel->rb);
|
||||
}
|
||||
|
||||
|
@ -464,9 +463,8 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip)
|
|||
sunxi_nand->selected = chip;
|
||||
}
|
||||
|
||||
static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
|
||||
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
|
||||
int ret;
|
||||
|
@ -502,10 +500,9 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
|||
}
|
||||
}
|
||||
|
||||
static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
|
||||
static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
|
||||
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
|
||||
int ret;
|
||||
|
@ -540,19 +537,18 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
|
|||
}
|
||||
}
|
||||
|
||||
static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
|
||||
static uint8_t sunxi_nfc_read_byte(struct nand_chip *nand)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
|
||||
sunxi_nfc_read_buf(mtd, &ret, 1);
|
||||
sunxi_nfc_read_buf(nand, &ret, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
|
||||
static void sunxi_nfc_cmd_ctrl(struct nand_chip *nand, int dat,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
|
||||
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
|
||||
int ret;
|
||||
|
@ -761,7 +757,7 @@ static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
|
|||
{
|
||||
sunxi_nfc_randomizer_config(mtd, page, ecc);
|
||||
sunxi_nfc_randomizer_enable(mtd);
|
||||
sunxi_nfc_write_buf(mtd, buf, len);
|
||||
sunxi_nfc_write_buf(mtd_to_nand(mtd), buf, len);
|
||||
sunxi_nfc_randomizer_disable(mtd);
|
||||
}
|
||||
|
||||
|
@ -770,7 +766,7 @@ static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
|
|||
{
|
||||
sunxi_nfc_randomizer_config(mtd, page, ecc);
|
||||
sunxi_nfc_randomizer_enable(mtd);
|
||||
sunxi_nfc_read_buf(mtd, buf, len);
|
||||
sunxi_nfc_read_buf(mtd_to_nand(mtd), buf, len);
|
||||
sunxi_nfc_randomizer_disable(mtd);
|
||||
}
|
||||
|
||||
|
@ -995,7 +991,7 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
|
|||
false);
|
||||
|
||||
if (!randomize)
|
||||
sunxi_nfc_read_buf(mtd, oob + offset, len);
|
||||
sunxi_nfc_read_buf(nand, oob + offset, len);
|
||||
else
|
||||
sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
|
||||
false, page);
|
||||
|
@ -1189,10 +1185,10 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
|
|||
*cur_off = mtd->oobsize + mtd->writesize;
|
||||
}
|
||||
|
||||
static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, uint8_t *buf,
|
||||
static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *chip, uint8_t *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
unsigned int max_bitflips = 0;
|
||||
int ret, i, cur_off = 0;
|
||||
|
@ -1227,10 +1223,10 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
|
|||
return max_bitflips;
|
||||
}
|
||||
|
||||
static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u8 *buf,
|
||||
static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *chip, u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
int ret;
|
||||
|
||||
nand_read_page_op(chip, page, 0, NULL, 0);
|
||||
|
@ -1241,14 +1237,14 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
|
|||
return ret;
|
||||
|
||||
/* Fallback to PIO mode */
|
||||
return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page);
|
||||
return sunxi_nfc_hw_ecc_read_page(chip, buf, oob_required, page);
|
||||
}
|
||||
|
||||
static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int sunxi_nfc_hw_ecc_read_subpage(struct nand_chip *chip,
|
||||
u32 data_offs, u32 readlen,
|
||||
u8 *bufpoi, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
int ret, i, cur_off = 0;
|
||||
unsigned int max_bitflips = 0;
|
||||
|
@ -1278,11 +1274,11 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
|
|||
return max_bitflips;
|
||||
}
|
||||
|
||||
static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip *chip,
|
||||
u32 data_offs, u32 readlen,
|
||||
u8 *buf, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
|
||||
int ret;
|
||||
|
||||
|
@ -1293,15 +1289,15 @@ static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
|
|||
return ret;
|
||||
|
||||
/* Fallback to PIO mode */
|
||||
return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen,
|
||||
return sunxi_nfc_hw_ecc_read_subpage(chip, data_offs, readlen,
|
||||
buf, page);
|
||||
}
|
||||
|
||||
static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *chip,
|
||||
const uint8_t *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
int ret, i, cur_off = 0;
|
||||
|
||||
|
@ -1331,12 +1327,12 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
|
|||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int sunxi_nfc_hw_ecc_write_subpage(struct nand_chip *chip,
|
||||
u32 data_offs, u32 data_len,
|
||||
const u8 *buf, int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
int ret, i, cur_off = 0;
|
||||
|
||||
|
@ -1363,12 +1359,12 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
|
|||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *chip,
|
||||
const u8 *buf,
|
||||
int oob_required,
|
||||
int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
|
||||
struct nand_ecc_ctrl *ecc = &nand->ecc;
|
||||
|
@ -1425,28 +1421,25 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
|
|||
return nand_prog_page_end_op(chip);
|
||||
|
||||
pio_fallback:
|
||||
return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page);
|
||||
return sunxi_nfc_hw_ecc_write_page(chip, buf, oob_required, page);
|
||||
}
|
||||
|
||||
static int sunxi_nfc_hw_ecc_read_oob(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
int page)
|
||||
static int sunxi_nfc_hw_ecc_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
chip->pagebuf = -1;
|
||||
|
||||
return chip->ecc.read_page(mtd, chip, chip->data_buf, 1, page);
|
||||
return chip->ecc.read_page(chip, chip->data_buf, 1, page);
|
||||
}
|
||||
|
||||
static int sunxi_nfc_hw_ecc_write_oob(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
int page)
|
||||
static int sunxi_nfc_hw_ecc_write_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
int ret;
|
||||
|
||||
chip->pagebuf = -1;
|
||||
|
||||
memset(chip->data_buf, 0xff, mtd->writesize);
|
||||
ret = chip->ecc.write_page(mtd, chip, chip->data_buf, 1, page);
|
||||
ret = chip->ecc.write_page(chip, chip->data_buf, 1, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1475,10 +1468,9 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
|
|||
#define sunxi_nand_lookup_timing(l, p, c) \
|
||||
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
|
||||
|
||||
static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
|
||||
static int sunxi_nfc_setup_data_interface(struct nand_chip *nand, int csline,
|
||||
const struct nand_data_interface *conf)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
|
||||
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
|
||||
const struct nand_sdr_timings *timings;
|
||||
|
@ -1920,7 +1912,7 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
|
|||
|
||||
nand = &chip->nand;
|
||||
/* Default tR value specified in the ONFI spec (chapter 4.15.1) */
|
||||
nand->chip_delay = 200;
|
||||
nand->legacy.chip_delay = 200;
|
||||
nand->controller = &nfc->controller;
|
||||
nand->controller->ops = &sunxi_nand_controller_ops;
|
||||
|
||||
|
@ -1931,23 +1923,23 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
|
|||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand_set_flash_node(nand, np);
|
||||
nand->select_chip = sunxi_nfc_select_chip;
|
||||
nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
|
||||
nand->read_buf = sunxi_nfc_read_buf;
|
||||
nand->write_buf = sunxi_nfc_write_buf;
|
||||
nand->read_byte = sunxi_nfc_read_byte;
|
||||
nand->legacy.cmd_ctrl = sunxi_nfc_cmd_ctrl;
|
||||
nand->legacy.read_buf = sunxi_nfc_read_buf;
|
||||
nand->legacy.write_buf = sunxi_nfc_write_buf;
|
||||
nand->legacy.read_byte = sunxi_nfc_read_byte;
|
||||
nand->setup_data_interface = sunxi_nfc_setup_data_interface;
|
||||
|
||||
mtd = nand_to_mtd(nand);
|
||||
mtd->dev.parent = dev;
|
||||
|
||||
ret = nand_scan(mtd, nsels);
|
||||
ret = nand_scan(nand, nsels);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mtd_device_register(mtd, NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register mtd device: %d\n", ret);
|
||||
nand_release(mtd);
|
||||
nand_release(nand);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1986,7 +1978,7 @@ static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
|
|||
while (!list_empty(&nfc->chips)) {
|
||||
chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip,
|
||||
node);
|
||||
nand_release(nand_to_mtd(&chip->nand));
|
||||
nand_release(&chip->nand);
|
||||
sunxi_nand_ecc_cleanup(&chip->nand.ecc);
|
||||
list_del(&chip->node);
|
||||
}
|
||||
|
|
|
@ -116,9 +116,9 @@ struct tango_chip {
|
|||
|
||||
#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
|
||||
|
||||
static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
|
||||
static void tango_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
|
||||
{
|
||||
struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
|
||||
struct tango_chip *tchip = to_tango_chip(chip);
|
||||
|
||||
if (ctrl & NAND_CLE)
|
||||
writeb_relaxed(dat, tchip->base + PBUS_CMD);
|
||||
|
@ -127,38 +127,36 @@ static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
|
|||
writeb_relaxed(dat, tchip->base + PBUS_ADDR);
|
||||
}
|
||||
|
||||
static int tango_dev_ready(struct mtd_info *mtd)
|
||||
static int tango_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
|
||||
|
||||
return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
|
||||
}
|
||||
|
||||
static u8 tango_read_byte(struct mtd_info *mtd)
|
||||
static u8 tango_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
|
||||
struct tango_chip *tchip = to_tango_chip(chip);
|
||||
|
||||
return readb_relaxed(tchip->base + PBUS_DATA);
|
||||
}
|
||||
|
||||
static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len)
|
||||
static void tango_read_buf(struct nand_chip *chip, u8 *buf, int len)
|
||||
{
|
||||
struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
|
||||
struct tango_chip *tchip = to_tango_chip(chip);
|
||||
|
||||
ioread8_rep(tchip->base + PBUS_DATA, buf, len);
|
||||
}
|
||||
|
||||
static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
|
||||
static void tango_write_buf(struct nand_chip *chip, const u8 *buf, int len)
|
||||
{
|
||||
struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd));
|
||||
struct tango_chip *tchip = to_tango_chip(chip);
|
||||
|
||||
iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
|
||||
}
|
||||
|
||||
static void tango_select_chip(struct mtd_info *mtd, int idx)
|
||||
static void tango_select_chip(struct nand_chip *chip, int idx)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
|
||||
struct tango_chip *tchip = to_tango_chip(chip);
|
||||
|
||||
|
@ -277,14 +275,15 @@ dma_unmap:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
u8 *buf, int oob_required, int page)
|
||||
static int tango_read_page(struct nand_chip *chip, u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
|
||||
int err, res, len = mtd->writesize;
|
||||
|
||||
if (oob_required)
|
||||
chip->ecc.read_oob(mtd, chip, page);
|
||||
chip->ecc.read_oob(chip, page);
|
||||
|
||||
err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page);
|
||||
if (err)
|
||||
|
@ -292,16 +291,17 @@ static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
|
||||
res = decode_error_report(chip);
|
||||
if (res < 0) {
|
||||
chip->ecc.read_oob_raw(mtd, chip, page);
|
||||
chip->ecc.read_oob_raw(chip, page);
|
||||
res = check_erased_page(chip, buf);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const u8 *buf, int oob_required, int page)
|
||||
static int tango_write_page(struct nand_chip *chip, const u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
|
||||
int err, status, len = mtd->writesize;
|
||||
|
||||
|
@ -314,7 +314,7 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
status = chip->waitfunc(mtd, chip);
|
||||
status = chip->legacy.waitfunc(chip);
|
||||
if (status & NAND_STATUS_FAIL)
|
||||
return -EIO;
|
||||
|
||||
|
@ -323,30 +323,26 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
|
||||
static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
*pos += len;
|
||||
|
||||
if (!*buf) {
|
||||
/* skip over "len" bytes */
|
||||
nand_change_read_column_op(chip, *pos, NULL, 0, false);
|
||||
} else {
|
||||
tango_read_buf(mtd, *buf, len);
|
||||
tango_read_buf(chip, *buf, len);
|
||||
*buf += len;
|
||||
}
|
||||
}
|
||||
|
||||
static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
*pos += len;
|
||||
|
||||
if (!*buf) {
|
||||
/* skip over "len" bytes */
|
||||
nand_change_write_column_op(chip, *pos, NULL, 0, false);
|
||||
} else {
|
||||
tango_write_buf(mtd, *buf, len);
|
||||
tango_write_buf(chip, *buf, len);
|
||||
*buf += len;
|
||||
}
|
||||
}
|
||||
|
@ -424,32 +420,30 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
|
|||
aux_write(chip, &oob, ecc_size, &pos);
|
||||
}
|
||||
|
||||
static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
u8 *buf, int oob_required, int page)
|
||||
static int tango_read_page_raw(struct nand_chip *chip, u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
nand_read_page_op(chip, page, 0, NULL, 0);
|
||||
raw_read(chip, buf, chip->oob_poi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
const u8 *buf, int oob_required, int page)
|
||||
static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
|
||||
raw_write(chip, buf, chip->oob_poi);
|
||||
return nand_prog_page_end_op(chip);
|
||||
}
|
||||
|
||||
static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int tango_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
nand_read_page_op(chip, page, 0, NULL, 0);
|
||||
raw_read(chip, NULL, chip->oob_poi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int tango_write_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
|
||||
raw_write(chip, NULL, chip->oob_poi);
|
||||
|
@ -485,11 +479,10 @@ static u32 to_ticks(int kHz, int ps)
|
|||
return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC);
|
||||
}
|
||||
|
||||
static int tango_set_timings(struct mtd_info *mtd, int csline,
|
||||
static int tango_set_timings(struct nand_chip *chip, int csline,
|
||||
const struct nand_data_interface *conf)
|
||||
{
|
||||
const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
|
||||
struct tango_chip *tchip = to_tango_chip(chip);
|
||||
u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr;
|
||||
|
@ -571,12 +564,12 @@ static int chip_init(struct device *dev, struct device_node *np)
|
|||
ecc = &chip->ecc;
|
||||
mtd = nand_to_mtd(chip);
|
||||
|
||||
chip->read_byte = tango_read_byte;
|
||||
chip->write_buf = tango_write_buf;
|
||||
chip->read_buf = tango_read_buf;
|
||||
chip->legacy.read_byte = tango_read_byte;
|
||||
chip->legacy.write_buf = tango_write_buf;
|
||||
chip->legacy.read_buf = tango_read_buf;
|
||||
chip->select_chip = tango_select_chip;
|
||||
chip->cmd_ctrl = tango_cmd_ctrl;
|
||||
chip->dev_ready = tango_dev_ready;
|
||||
chip->legacy.cmd_ctrl = tango_cmd_ctrl;
|
||||
chip->legacy.dev_ready = tango_dev_ready;
|
||||
chip->setup_data_interface = tango_set_timings;
|
||||
chip->options = NAND_USE_BOUNCE_BUFFER |
|
||||
NAND_NO_SUBPAGE_WRITE |
|
||||
|
@ -588,7 +581,7 @@ static int chip_init(struct device *dev, struct device_node *np)
|
|||
mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops);
|
||||
mtd->dev.parent = dev;
|
||||
|
||||
err = nand_scan(mtd, 1);
|
||||
err = nand_scan(chip, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -617,7 +610,7 @@ static int tango_nand_remove(struct platform_device *pdev)
|
|||
|
||||
for (cs = 0; cs < MAX_CS; ++cs) {
|
||||
if (nfc->chips[cs])
|
||||
nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip));
|
||||
nand_release(&nfc->chips[cs]->nand_chip);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -462,9 +462,8 @@ static int tegra_nand_exec_op(struct nand_chip *chip,
|
|||
check_only);
|
||||
}
|
||||
|
||||
static void tegra_nand_select_chip(struct mtd_info *mtd, int die_nr)
|
||||
static void tegra_nand_select_chip(struct nand_chip *chip, int die_nr)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct tegra_nand_chip *nand = to_tegra_chip(chip);
|
||||
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
|
||||
|
||||
|
@ -615,44 +614,46 @@ err_unmap_dma_page:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_nand_read_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u8 *buf,
|
||||
static int tegra_nand_read_page_raw(struct nand_chip *chip, u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
void *oob_buf = oob_required ? chip->oob_poi : NULL;
|
||||
|
||||
return tegra_nand_page_xfer(mtd, chip, buf, oob_buf,
|
||||
mtd->oobsize, page, true);
|
||||
}
|
||||
|
||||
static int tegra_nand_write_page_raw(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const u8 *buf,
|
||||
static int tegra_nand_write_page_raw(struct nand_chip *chip, const u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
void *oob_buf = oob_required ? chip->oob_poi : NULL;
|
||||
|
||||
return tegra_nand_page_xfer(mtd, chip, (void *)buf, oob_buf,
|
||||
mtd->oobsize, page, false);
|
||||
}
|
||||
|
||||
static int tegra_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int tegra_nand_read_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
return tegra_nand_page_xfer(mtd, chip, NULL, chip->oob_poi,
|
||||
mtd->oobsize, page, true);
|
||||
}
|
||||
|
||||
static int tegra_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int page)
|
||||
static int tegra_nand_write_oob(struct nand_chip *chip, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
return tegra_nand_page_xfer(mtd, chip, NULL, chip->oob_poi,
|
||||
mtd->oobsize, page, false);
|
||||
}
|
||||
|
||||
static int tegra_nand_read_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u8 *buf,
|
||||
static int tegra_nand_read_page_hwecc(struct nand_chip *chip, u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
|
||||
struct tegra_nand_chip *nand = to_tegra_chip(chip);
|
||||
void *oob_buf = oob_required ? chip->oob_poi : NULL;
|
||||
|
@ -716,7 +717,7 @@ static int tegra_nand_read_page_hwecc(struct mtd_info *mtd,
|
|||
* erased or if error correction just failed for all sub-
|
||||
* pages.
|
||||
*/
|
||||
ret = tegra_nand_read_oob(mtd, chip, page);
|
||||
ret = tegra_nand_read_oob(chip, page);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -759,10 +760,10 @@ static int tegra_nand_read_page_hwecc(struct mtd_info *mtd,
|
|||
}
|
||||
}
|
||||
|
||||
static int tegra_nand_write_page_hwecc(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, const u8 *buf,
|
||||
static int tegra_nand_write_page_hwecc(struct nand_chip *chip, const u8 *buf,
|
||||
int oob_required, int page)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
|
||||
void *oob_buf = oob_required ? chip->oob_poi : NULL;
|
||||
int ret;
|
||||
|
@ -813,10 +814,9 @@ static void tegra_nand_setup_timing(struct tegra_nand_controller *ctrl,
|
|||
writel_relaxed(reg, ctrl->regs + TIMING_2);
|
||||
}
|
||||
|
||||
static int tegra_nand_setup_data_interface(struct mtd_info *mtd, int csline,
|
||||
static int tegra_nand_setup_data_interface(struct nand_chip *chip, int csline,
|
||||
const struct nand_data_interface *conf)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller);
|
||||
const struct nand_sdr_timings *timings;
|
||||
|
||||
|
@ -1119,7 +1119,7 @@ static int tegra_nand_chips_init(struct device *dev,
|
|||
chip->select_chip = tegra_nand_select_chip;
|
||||
chip->setup_data_interface = tegra_nand_setup_data_interface;
|
||||
|
||||
ret = nand_scan(mtd, 1);
|
||||
ret = nand_scan(chip, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -126,11 +126,10 @@ static inline struct tmio_nand *mtd_to_tmio(struct mtd_info *mtd)
|
|||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
static void tmio_nand_hwcontrol(struct nand_chip *chip, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct tmio_nand *tmio = mtd_to_tmio(mtd);
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
u8 mode;
|
||||
|
@ -156,12 +155,12 @@ static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
|
|||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
tmio_iowrite8(cmd, chip->IO_ADDR_W);
|
||||
tmio_iowrite8(cmd, chip->legacy.IO_ADDR_W);
|
||||
}
|
||||
|
||||
static int tmio_nand_dev_ready(struct mtd_info *mtd)
|
||||
static int tmio_nand_dev_ready(struct nand_chip *chip)
|
||||
{
|
||||
struct tmio_nand *tmio = mtd_to_tmio(mtd);
|
||||
struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
|
||||
|
||||
return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY);
|
||||
}
|
||||
|
@ -187,10 +186,9 @@ static irqreturn_t tmio_irq(int irq, void *__tmio)
|
|||
*erase and write, we enable it to wake us up. The irq handler
|
||||
*disables the interrupt.
|
||||
*/
|
||||
static int
|
||||
tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
|
||||
static int tmio_nand_wait(struct nand_chip *nand_chip)
|
||||
{
|
||||
struct tmio_nand *tmio = mtd_to_tmio(mtd);
|
||||
struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(nand_chip));
|
||||
long timeout;
|
||||
u8 status;
|
||||
|
||||
|
@ -199,10 +197,10 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
|
|||
tmio_iowrite8(0x81, tmio->fcr + FCR_IMR);
|
||||
|
||||
timeout = wait_event_timeout(nand_chip->controller->wq,
|
||||
tmio_nand_dev_ready(mtd),
|
||||
tmio_nand_dev_ready(nand_chip),
|
||||
msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20));
|
||||
|
||||
if (unlikely(!tmio_nand_dev_ready(mtd))) {
|
||||
if (unlikely(!tmio_nand_dev_ready(nand_chip))) {
|
||||
tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
|
||||
dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n",
|
||||
nand_chip->state == FL_ERASING ? "erase" : "program",
|
||||
|
@ -225,9 +223,9 @@ tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
|
|||
*To prevent stale data from being read, tmio_nand_hwcontrol() clears
|
||||
*tmio->read_good.
|
||||
*/
|
||||
static u_char tmio_nand_read_byte(struct mtd_info *mtd)
|
||||
static u_char tmio_nand_read_byte(struct nand_chip *chip)
|
||||
{
|
||||
struct tmio_nand *tmio = mtd_to_tmio(mtd);
|
||||
struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
|
||||
unsigned int data;
|
||||
|
||||
if (tmio->read_good--)
|
||||
|
@ -245,33 +243,33 @@ static u_char tmio_nand_read_byte(struct mtd_info *mtd)
|
|||
*buffer functions.
|
||||
*/
|
||||
static void
|
||||
tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||
tmio_nand_write_buf(struct nand_chip *chip, const u_char *buf, int len)
|
||||
{
|
||||
struct tmio_nand *tmio = mtd_to_tmio(mtd);
|
||||
struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
|
||||
|
||||
tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
|
||||
}
|
||||
|
||||
static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
static void tmio_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
|
||||
{
|
||||
struct tmio_nand *tmio = mtd_to_tmio(mtd);
|
||||
struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
|
||||
|
||||
tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
|
||||
}
|
||||
|
||||
static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
static void tmio_nand_enable_hwecc(struct nand_chip *chip, int mode)
|
||||
{
|
||||
struct tmio_nand *tmio = mtd_to_tmio(mtd);
|
||||
struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
|
||||
|
||||
tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE);
|
||||
tmio_ioread8(tmio->fcr + FCR_DATA); /* dummy read */
|
||||
tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE);
|
||||
}
|
||||
|
||||
static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
||||
static int tmio_nand_calculate_ecc(struct nand_chip *chip, const u_char *dat,
|
||||
u_char *ecc_code)
|
||||
{
|
||||
struct tmio_nand *tmio = mtd_to_tmio(mtd);
|
||||
struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
|
||||
unsigned int ecc;
|
||||
|
||||
tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE);
|
||||
|
@ -290,16 +288,18 @@ static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||
unsigned char *read_ecc, unsigned char *calc_ecc)
|
||||
static int tmio_nand_correct_data(struct nand_chip *chip, unsigned char *buf,
|
||||
unsigned char *read_ecc,
|
||||
unsigned char *calc_ecc)
|
||||
{
|
||||
int r0, r1;
|
||||
|
||||
/* assume ecc.size = 512 and ecc.bytes = 6 */
|
||||
r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256);
|
||||
r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256, false);
|
||||
if (r0 < 0)
|
||||
return r0;
|
||||
r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256);
|
||||
r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256,
|
||||
false);
|
||||
if (r1 < 0)
|
||||
return r1;
|
||||
return r0 + r1;
|
||||
|
@ -400,15 +400,15 @@ static int tmio_probe(struct platform_device *dev)
|
|||
return retval;
|
||||
|
||||
/* Set address of NAND IO lines */
|
||||
nand_chip->IO_ADDR_R = tmio->fcr;
|
||||
nand_chip->IO_ADDR_W = tmio->fcr;
|
||||
nand_chip->legacy.IO_ADDR_R = tmio->fcr;
|
||||
nand_chip->legacy.IO_ADDR_W = tmio->fcr;
|
||||
|
||||
/* Set address of hardware control function */
|
||||
nand_chip->cmd_ctrl = tmio_nand_hwcontrol;
|
||||
nand_chip->dev_ready = tmio_nand_dev_ready;
|
||||
nand_chip->read_byte = tmio_nand_read_byte;
|
||||
nand_chip->write_buf = tmio_nand_write_buf;
|
||||
nand_chip->read_buf = tmio_nand_read_buf;
|
||||
nand_chip->legacy.cmd_ctrl = tmio_nand_hwcontrol;
|
||||
nand_chip->legacy.dev_ready = tmio_nand_dev_ready;
|
||||
nand_chip->legacy.read_byte = tmio_nand_read_byte;
|
||||
nand_chip->legacy.write_buf = tmio_nand_write_buf;
|
||||
nand_chip->legacy.read_buf = tmio_nand_read_buf;
|
||||
|
||||
/* set eccmode using hardware ECC */
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
|
@ -423,7 +423,7 @@ static int tmio_probe(struct platform_device *dev)
|
|||
nand_chip->badblock_pattern = data->badblock_pattern;
|
||||
|
||||
/* 15 us command delay time */
|
||||
nand_chip->chip_delay = 15;
|
||||
nand_chip->legacy.chip_delay = 15;
|
||||
|
||||
retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0,
|
||||
dev_name(&dev->dev), tmio);
|
||||
|
@ -433,10 +433,10 @@ static int tmio_probe(struct platform_device *dev)
|
|||
}
|
||||
|
||||
tmio->irq = irq;
|
||||
nand_chip->waitfunc = tmio_nand_wait;
|
||||
nand_chip->legacy.waitfunc = tmio_nand_wait;
|
||||
|
||||
/* Scan to find existence of the device */
|
||||
retval = nand_scan(mtd, 1);
|
||||
retval = nand_scan(nand_chip, 1);
|
||||
if (retval)
|
||||
goto err_irq;
|
||||
|
||||
|
@ -449,7 +449,7 @@ static int tmio_probe(struct platform_device *dev)
|
|||
if (!retval)
|
||||
return retval;
|
||||
|
||||
nand_release(mtd);
|
||||
nand_release(nand_chip);
|
||||
|
||||
err_irq:
|
||||
tmio_hw_stop(dev, tmio);
|
||||
|
@ -460,7 +460,7 @@ static int tmio_remove(struct platform_device *dev)
|
|||
{
|
||||
struct tmio_nand *tmio = platform_get_drvdata(dev);
|
||||
|
||||
nand_release(nand_to_mtd(&tmio->chip));
|
||||
nand_release(&tmio->chip);
|
||||
tmio_hw_stop(dev, tmio);
|
||||
return 0;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue