mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
* MTD changes:
Apart from a binding conversion to yaml, only minor changes/small fixes have been merged. * Raw NAND changes: Various controller drivers received minor fixes like DMA mapping checks, better timing derivations or bitflip statistics. It has also been discovered that some Hynix NAND flashes were not supporting read-retries, which is not properly supported. * SPI NAND changes: In order to support high-speed modes, certain chips need extra configuration like adding more dummy cycles. This is now possible, especially on Winbond chips. Aside from that, Gigadevice gets support for a new chip (GD5F1GM9). * SPI NOR changes: A notable changes is the fix for exiting 4-byte addressing on Infineon SEMPER flashes. These flashes do not support the standard EX4B opcode (E9h), and use a vendor-specific opcode (B8h) instead. There is also a fix for unlocking flashes that are write-protected at power-on. This was caused by using an uninitialized mtd_info in spi_nor_try_unlock_all(). -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEE9HuaYnbmDhq/XIDIJWrqGEe9VoQFAmiLn/sACgkQJWrqGEe9 VoTGowf/c6kynDuMlQbTANv/UIYX/LRFZsnIx0LB32LWrhLaUIBsbFxejyt07WG9 ryej+xRUtSHGsqMIw+B/PjvA4hUNLdsSwO/udIwstXNQjJcO9OKp/ucpvlxLzIha REq8IifvT9vLLA+Efoq2L25dM14KjuFCAjwm3GH/SmdTOqPhI/Bbnx4vRWIPeXrx XZ69ovIiu5NqLTD5IFGsu+omhbFWlDtVALtKNknrTOXWrjLZhDpieO4f7M9rvru6 OwazFQAWuixzqZRMFqvOzu8KUDnOHi9gHrzi6tS7T1zBUDz9ywdBtaHYCd7VlMJh uV1wjUdWjnIh9E8R/llv3D+ko1Ya1w== =IS/d -----END PGP SIGNATURE----- Merge tag 'mtd/for-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux Pull mtd updates from Miquel Raynal: "MTD changes: - Apart from a binding conversion to yaml, only minor changes/small fixes have been merged. Raw NAND changes: - Minor fixes for various controller drivers like DMA mapping checks, better timing derivations or bitflip statistics. - some Hynix NAND flashes were not supporting read-retries, so don't even try to do it SPI NAND changes: - In order to support high-speed modes, certain chips need extra configuration like adding more dummy cycles. This is now possible, especially on Winbond chips. - Aside from that, Gigadevice gets support for a new chip (GD5F1GM9). SPI NOR changes: - A notable changes is the fix for exiting 4-byte addressing on Infineon SEMPER flashes. These flashes do not support the standard EX4B opcode (E9h), and use a vendor-specific opcode (B8h) instead. - There is also a fix for unlocking flashes that are write-protected at power-on. This was caused by using an uninitialized mtd_info in spi_nor_try_unlock_all()" * tag 'mtd/for-6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (26 commits) mtd: spinand: winbond: Add comment about the maximum frequency mtd: spinand: winbond: Enable high-speed modes on w35n0xjw mtd: spinand: winbond: Enable high-speed modes on w25n0xjw mtd: spinand: Add a ->configure_chip() hook mtd: spinand: Add a frequency field to all READ_FROM_CACHE variants mtd: spinand: Fix macro alignment spi: spi-mem: Take into account the actual maximum frequency spi: spi-mem: Use picoseconds for calculating the op durations mtd: rawnand: atmel: set pmecc data setup time mtd: spinand: propagate spinand_wait() errors from spinand_write_page() mtd: rawnand: fsmc: Add missing check after DMA map mtd: rawnand: rockchip: Add missing check after DMA map mtd: rawnand: hynix: don't try read-retry on SLC NANDs mtd: rawnand: atmel: Fix dma_mapping_error() address mtd: nand: brcmnand: fix mtd corrected bits stat mtd: rawnand: renesas: Add missing check after DMA map mtd: spinand: gigadevice: Add support for GD5F1GM9 chips mtd: nand: brcmnand: replace manual string choices with standard helpers mtd: map: Don't use "proxy" headers mtd: spi-nor: Fix spi_nor_try_unlock_all() ...
This commit is contained in:
commit
cbbf0a759f
32 changed files with 556 additions and 258 deletions
|
@ -20,7 +20,7 @@ properties:
|
|||
- pattern: "^((((micron|spansion|st),)?\
|
||||
(m25p(40|80|16|32|64|128)|\
|
||||
n25q(32b|064|128a11|128a13|256a|512a|164k)))|\
|
||||
atmel,at25df(321a|641|081a)|\
|
||||
atmel,at(25|26)df(321a|641|081a)|\
|
||||
everspin,mr25h(10|40|128|256)|\
|
||||
(mxicy|macronix),mx25l(4005a|1606e|6405d|8005|12805d|25635e)|\
|
||||
(mxicy|macronix),mx25u(4033|4035)|\
|
||||
|
|
74
Documentation/devicetree/bindings/mtd/nxp,lpc1773-spifi.yaml
Normal file
74
Documentation/devicetree/bindings/mtd/nxp,lpc1773-spifi.yaml
Normal file
|
@ -0,0 +1,74 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/nxp,lpc1773-spifi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP SPI Flash Interface (SPIFI)
|
||||
|
||||
description:
|
||||
NXP SPIFI is a specialized SPI interface for serial Flash devices.
|
||||
It supports one Flash device with 1-, 2- and 4-bits width in SPI
|
||||
mode 0 or 3. The controller operates in either command or memory
|
||||
mode. In memory mode the Flash is accessible from the CPU as
|
||||
normal memory.
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nxp,lpc1773-spifi
|
||||
|
||||
reg:
|
||||
maxItems: 2
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: spifi
|
||||
- const: flash
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: spifi
|
||||
- const: reg
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
spi-cpol:
|
||||
enum: [0, 3]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-controller.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/lpc18xx-ccu.h>
|
||||
|
||||
spi@40003000 {
|
||||
compatible = "nxp,lpc1773-spifi";
|
||||
reg = <0x40003000 0x1000>, <0x14000000 0x4000000>;
|
||||
reg-names = "spifi", "flash";
|
||||
interrupts = <30>;
|
||||
clocks = <&ccu1 CLK_SPIFI>, <&ccu1 CLK_CPU_SPIFI>;
|
||||
clock-names = "spifi", "reg";
|
||||
resets = <&rgu 53>;
|
||||
};
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
* NXP SPI Flash Interface (SPIFI)
|
||||
|
||||
NXP SPIFI is a specialized SPI interface for serial Flash devices.
|
||||
It supports one Flash device with 1-, 2- and 4-bits width in SPI
|
||||
mode 0 or 3. The controller operates in either command or memory
|
||||
mode. In memory mode the Flash is accessible from the CPU as
|
||||
normal memory.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "nxp,lpc1773-spifi"
|
||||
- reg : the first contains the register location and length,
|
||||
the second contains the memory mapping address and length
|
||||
- reg-names: Should contain the reg names "spifi" and "flash"
|
||||
- interrupts : Should contain the interrupt for the device
|
||||
- clocks : The clocks needed by the SPIFI controller
|
||||
- clock-names : Should contain the clock names "spifi" and "reg"
|
||||
|
||||
Optional properties:
|
||||
- resets : phandle + reset specifier
|
||||
|
||||
The SPI Flash must be a child of the SPIFI node and must have a
|
||||
compatible property as specified in bindings/mtd/jedec,spi-nor.txt
|
||||
|
||||
Optionally it can also contain the following properties.
|
||||
- spi-cpol : Controller only supports mode 0 and 3 so either
|
||||
both spi-cpol and spi-cpha should be present or
|
||||
none of them
|
||||
- spi-cpha : See above
|
||||
- spi-rx-bus-width : Used to select how many pins that are used
|
||||
for input on the controller
|
||||
|
||||
See bindings/spi/spi-bus.txt for more information.
|
||||
|
||||
Example:
|
||||
spifi: spifi@40003000 {
|
||||
compatible = "nxp,lpc1773-spifi";
|
||||
reg = <0x40003000 0x1000>, <0x14000000 0x4000000>;
|
||||
reg-names = "spifi", "flash";
|
||||
interrupts = <30>;
|
||||
clocks = <&ccu1 CLK_SPIFI>, <&ccu1 CLK_CPU_SPIFI>;
|
||||
clock-names = "spifi", "reg";
|
||||
resets = <&rgu 53>;
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
spi-rx-bus-width = <4>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "data";
|
||||
reg = <0 0x200000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -344,7 +344,7 @@ static int erase_xfer(partition_t *part,
|
|||
return -ENOMEM;
|
||||
|
||||
erase->addr = xfer->Offset;
|
||||
erase->len = 1 << part->header.EraseUnitSize;
|
||||
erase->len = 1ULL << part->header.EraseUnitSize;
|
||||
|
||||
ret = mtd_erase(part->mbd.mtd, erase);
|
||||
if (!ret) {
|
||||
|
|
|
@ -373,7 +373,7 @@ static int atmel_nand_dma_transfer(struct atmel_nand_controller *nc,
|
|||
dma_cookie_t cookie;
|
||||
|
||||
buf_dma = dma_map_single(nc->dev, buf, len, dir);
|
||||
if (dma_mapping_error(nc->dev, dev_dma)) {
|
||||
if (dma_mapping_error(nc->dev, buf_dma)) {
|
||||
dev_err(nc->dev,
|
||||
"Failed to prepare a buffer for DMA access\n");
|
||||
goto err;
|
||||
|
|
|
@ -143,6 +143,7 @@ struct atmel_pmecc_caps {
|
|||
int nstrengths;
|
||||
int el_offset;
|
||||
bool correct_erased_chunks;
|
||||
bool clk_ctrl;
|
||||
};
|
||||
|
||||
struct atmel_pmecc {
|
||||
|
@ -843,6 +844,10 @@ static struct atmel_pmecc *atmel_pmecc_create(struct platform_device *pdev,
|
|||
if (IS_ERR(pmecc->regs.errloc))
|
||||
return ERR_CAST(pmecc->regs.errloc);
|
||||
|
||||
/* pmecc data setup time */
|
||||
if (caps->clk_ctrl)
|
||||
writel(PMECC_CLK_133MHZ, pmecc->regs.base + ATMEL_PMECC_CLK);
|
||||
|
||||
/* Disable all interrupts before registering the PMECC handler. */
|
||||
writel(0xffffffff, pmecc->regs.base + ATMEL_PMECC_IDR);
|
||||
atmel_pmecc_reset(pmecc);
|
||||
|
@ -896,6 +901,7 @@ static struct atmel_pmecc_caps at91sam9g45_caps = {
|
|||
.strengths = atmel_pmecc_strengths,
|
||||
.nstrengths = 5,
|
||||
.el_offset = 0x8c,
|
||||
.clk_ctrl = true,
|
||||
};
|
||||
|
||||
static struct atmel_pmecc_caps sama5d4_caps = {
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/static_key.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/string_choices.h>
|
||||
|
||||
#include "brcmnand.h"
|
||||
|
||||
|
@ -359,6 +360,7 @@ enum brcmnand_reg {
|
|||
BRCMNAND_CORR_THRESHOLD_EXT,
|
||||
BRCMNAND_UNCORR_COUNT,
|
||||
BRCMNAND_CORR_COUNT,
|
||||
BRCMNAND_READ_ERROR_COUNT,
|
||||
BRCMNAND_CORR_EXT_ADDR,
|
||||
BRCMNAND_CORR_ADDR,
|
||||
BRCMNAND_UNCORR_EXT_ADDR,
|
||||
|
@ -389,6 +391,7 @@ static const u16 brcmnand_regs_v21[] = {
|
|||
[BRCMNAND_CORR_THRESHOLD_EXT] = 0,
|
||||
[BRCMNAND_UNCORR_COUNT] = 0,
|
||||
[BRCMNAND_CORR_COUNT] = 0,
|
||||
[BRCMNAND_READ_ERROR_COUNT] = 0,
|
||||
[BRCMNAND_CORR_EXT_ADDR] = 0x60,
|
||||
[BRCMNAND_CORR_ADDR] = 0x64,
|
||||
[BRCMNAND_UNCORR_EXT_ADDR] = 0x68,
|
||||
|
@ -419,6 +422,7 @@ static const u16 brcmnand_regs_v33[] = {
|
|||
[BRCMNAND_CORR_THRESHOLD_EXT] = 0,
|
||||
[BRCMNAND_UNCORR_COUNT] = 0,
|
||||
[BRCMNAND_CORR_COUNT] = 0,
|
||||
[BRCMNAND_READ_ERROR_COUNT] = 0x80,
|
||||
[BRCMNAND_CORR_EXT_ADDR] = 0x70,
|
||||
[BRCMNAND_CORR_ADDR] = 0x74,
|
||||
[BRCMNAND_UNCORR_EXT_ADDR] = 0x78,
|
||||
|
@ -449,6 +453,7 @@ static const u16 brcmnand_regs_v50[] = {
|
|||
[BRCMNAND_CORR_THRESHOLD_EXT] = 0,
|
||||
[BRCMNAND_UNCORR_COUNT] = 0,
|
||||
[BRCMNAND_CORR_COUNT] = 0,
|
||||
[BRCMNAND_READ_ERROR_COUNT] = 0x80,
|
||||
[BRCMNAND_CORR_EXT_ADDR] = 0x70,
|
||||
[BRCMNAND_CORR_ADDR] = 0x74,
|
||||
[BRCMNAND_UNCORR_EXT_ADDR] = 0x78,
|
||||
|
@ -479,6 +484,7 @@ static const u16 brcmnand_regs_v60[] = {
|
|||
[BRCMNAND_CORR_THRESHOLD_EXT] = 0xc4,
|
||||
[BRCMNAND_UNCORR_COUNT] = 0xfc,
|
||||
[BRCMNAND_CORR_COUNT] = 0x100,
|
||||
[BRCMNAND_READ_ERROR_COUNT] = 0x104,
|
||||
[BRCMNAND_CORR_EXT_ADDR] = 0x10c,
|
||||
[BRCMNAND_CORR_ADDR] = 0x110,
|
||||
[BRCMNAND_UNCORR_EXT_ADDR] = 0x114,
|
||||
|
@ -509,6 +515,7 @@ static const u16 brcmnand_regs_v71[] = {
|
|||
[BRCMNAND_CORR_THRESHOLD_EXT] = 0xe0,
|
||||
[BRCMNAND_UNCORR_COUNT] = 0xfc,
|
||||
[BRCMNAND_CORR_COUNT] = 0x100,
|
||||
[BRCMNAND_READ_ERROR_COUNT] = 0x104,
|
||||
[BRCMNAND_CORR_EXT_ADDR] = 0x10c,
|
||||
[BRCMNAND_CORR_ADDR] = 0x110,
|
||||
[BRCMNAND_UNCORR_EXT_ADDR] = 0x114,
|
||||
|
@ -539,6 +546,7 @@ static const u16 brcmnand_regs_v72[] = {
|
|||
[BRCMNAND_CORR_THRESHOLD_EXT] = 0xe0,
|
||||
[BRCMNAND_UNCORR_COUNT] = 0xfc,
|
||||
[BRCMNAND_CORR_COUNT] = 0x100,
|
||||
[BRCMNAND_READ_ERROR_COUNT] = 0x104,
|
||||
[BRCMNAND_CORR_EXT_ADDR] = 0x10c,
|
||||
[BRCMNAND_CORR_ADDR] = 0x110,
|
||||
[BRCMNAND_UNCORR_EXT_ADDR] = 0x114,
|
||||
|
@ -959,11 +967,11 @@ static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs,
|
|||
return offs_cs0 + cs * ctrl->reg_spacing + cs_offs;
|
||||
}
|
||||
|
||||
static inline u32 brcmnand_count_corrected(struct brcmnand_controller *ctrl)
|
||||
static inline u32 brcmnand_corr_total(struct brcmnand_controller *ctrl)
|
||||
{
|
||||
if (ctrl->nand_version < 0x0600)
|
||||
return 1;
|
||||
return brcmnand_read_reg(ctrl, BRCMNAND_CORR_COUNT);
|
||||
if (ctrl->nand_version < 0x400)
|
||||
return 0;
|
||||
return brcmnand_read_reg(ctrl, BRCMNAND_READ_ERROR_COUNT);
|
||||
}
|
||||
|
||||
static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
|
||||
|
@ -1462,7 +1470,7 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp)
|
|||
int ret;
|
||||
|
||||
if (old_wp != wp) {
|
||||
dev_dbg(ctrl->dev, "WP %s\n", wp ? "on" : "off");
|
||||
dev_dbg(ctrl->dev, "WP %s\n", str_on_off(wp));
|
||||
old_wp = wp;
|
||||
}
|
||||
|
||||
|
@ -1492,7 +1500,7 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp)
|
|||
if (ret)
|
||||
dev_err_ratelimited(&host->pdev->dev,
|
||||
"nand #WP expected %s\n",
|
||||
wp ? "on" : "off");
|
||||
str_on_off(wp));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1869,8 +1877,8 @@ static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
|
|||
unsigned int trans = len >> FC_SHIFT;
|
||||
dma_addr_t pa;
|
||||
|
||||
dev_dbg(ctrl->dev, "EDU %s %p:%p\n", ((edu_cmd == EDU_CMD_READ) ?
|
||||
"read" : "write"), buf, oob);
|
||||
dev_dbg(ctrl->dev, "EDU %s %p:%p\n",
|
||||
str_read_write(edu_cmd == EDU_CMD_READ), buf, oob);
|
||||
|
||||
pa = dma_map_single(ctrl->dev, buf, len, dir);
|
||||
if (dma_mapping_error(ctrl->dev, pa)) {
|
||||
|
@ -2066,15 +2074,20 @@ static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
|
|||
*/
|
||||
static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
u64 addr, unsigned int trans, u32 *buf,
|
||||
u8 *oob, u64 *err_addr)
|
||||
u8 *oob, u64 *err_addr, unsigned int *corr)
|
||||
{
|
||||
struct brcmnand_host *host = nand_get_controller_data(chip);
|
||||
struct brcmnand_controller *ctrl = host->ctrl;
|
||||
int i, ret = 0;
|
||||
unsigned int prev_corr;
|
||||
|
||||
if (corr)
|
||||
*corr = 0;
|
||||
|
||||
brcmnand_clear_ecc_addr(ctrl);
|
||||
|
||||
for (i = 0; i < trans; i++, addr += FC_BYTES) {
|
||||
prev_corr = brcmnand_corr_total(ctrl);
|
||||
brcmnand_set_cmd_addr(mtd, addr);
|
||||
/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
|
||||
brcmnand_send_cmd(host, CMD_PAGE_READ);
|
||||
|
@ -2099,13 +2112,16 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
|
||||
if (*err_addr)
|
||||
ret = -EBADMSG;
|
||||
}
|
||||
else {
|
||||
*err_addr = brcmnand_get_correcc_addr(ctrl);
|
||||
|
||||
if (!ret) {
|
||||
*err_addr = brcmnand_get_correcc_addr(ctrl);
|
||||
if (*err_addr) {
|
||||
ret = -EUCLEAN;
|
||||
|
||||
if (*err_addr)
|
||||
ret = -EUCLEAN;
|
||||
if (corr && (brcmnand_corr_total(ctrl) - prev_corr) > *corr)
|
||||
*corr = brcmnand_corr_total(ctrl) - prev_corr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2173,6 +2189,8 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
|
|||
int err;
|
||||
bool retry = true;
|
||||
bool edu_err = false;
|
||||
unsigned int corrected = 0; /* max corrected bits per subpage */
|
||||
unsigned int prev_tot = brcmnand_corr_total(ctrl);
|
||||
|
||||
dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
|
||||
|
||||
|
@ -2200,9 +2218,11 @@ try_dmaread:
|
|||
memset(oob, 0x99, mtd->oobsize);
|
||||
|
||||
err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
|
||||
oob, &err_addr);
|
||||
oob, &err_addr, &corrected);
|
||||
}
|
||||
|
||||
mtd->ecc_stats.corrected += brcmnand_corr_total(ctrl) - prev_tot;
|
||||
|
||||
if (mtd_is_eccerr(err)) {
|
||||
/*
|
||||
* On controller version and 7.0, 7.1 , DMA read after a
|
||||
|
@ -2240,16 +2260,20 @@ try_dmaread:
|
|||
}
|
||||
|
||||
if (mtd_is_bitflip(err)) {
|
||||
unsigned int corrected = brcmnand_count_corrected(ctrl);
|
||||
|
||||
/* in case of EDU correctable error we read again using PIO */
|
||||
if (edu_err)
|
||||
err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
|
||||
oob, &err_addr);
|
||||
oob, &err_addr, &corrected);
|
||||
|
||||
dev_dbg(ctrl->dev, "corrected error at 0x%llx\n",
|
||||
(unsigned long long)err_addr);
|
||||
mtd->ecc_stats.corrected += corrected;
|
||||
/*
|
||||
* if flipped bits accumulator is not supported but we detected
|
||||
* a correction, increase stat by 1 to match previous behavior.
|
||||
*/
|
||||
if (brcmnand_corr_total(ctrl) == prev_tot)
|
||||
mtd->ecc_stats.corrected++;
|
||||
|
||||
/* Always exceed the software-imposed threshold */
|
||||
return max(mtd->bitflip_threshold, corrected);
|
||||
}
|
||||
|
|
|
@ -503,6 +503,8 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
|
|||
|
||||
dma_dev = chan->device;
|
||||
dma_addr = dma_map_single(dma_dev->dev, buffer, len, direction);
|
||||
if (dma_mapping_error(dma_dev->dev, dma_addr))
|
||||
return -EINVAL;
|
||||
|
||||
if (direction == DMA_TO_DEVICE) {
|
||||
dma_src = dma_addr;
|
||||
|
|
|
@ -377,9 +377,9 @@ static int hynix_nand_rr_init(struct nand_chip *chip)
|
|||
|
||||
/*
|
||||
* We only support read-retry for 1xnm NANDs, and those NANDs all
|
||||
* expose a valid JEDEC ID.
|
||||
* expose a valid JEDEC ID. SLC NANDs don't require read-retry.
|
||||
*/
|
||||
if (valid_jedecid) {
|
||||
if (valid_jedecid && nanddev_bits_per_cell(&chip->base) > 1) {
|
||||
u8 nand_tech = chip->id.data[5] >> 4;
|
||||
|
||||
/* 1xnm technology */
|
||||
|
|
|
@ -426,6 +426,9 @@ static int rnandc_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
|
|||
/* Configure DMA */
|
||||
dma_addr = dma_map_single(rnandc->dev, rnandc->buf, mtd->writesize,
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(rnandc->dev, dma_addr))
|
||||
return -ENOMEM;
|
||||
|
||||
writel(dma_addr, rnandc->regs + DMA_ADDR_LOW_REG);
|
||||
writel(mtd->writesize, rnandc->regs + DMA_CNT_REG);
|
||||
writel(DMA_TLVL_MAX, rnandc->regs + DMA_TLVL_REG);
|
||||
|
@ -606,6 +609,9 @@ static int rnandc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
|
|||
/* Configure DMA */
|
||||
dma_addr = dma_map_single(rnandc->dev, (void *)rnandc->buf, mtd->writesize,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(rnandc->dev, dma_addr))
|
||||
return -ENOMEM;
|
||||
|
||||
writel(dma_addr, rnandc->regs + DMA_ADDR_LOW_REG);
|
||||
writel(mtd->writesize, rnandc->regs + DMA_CNT_REG);
|
||||
writel(DMA_TLVL_MAX, rnandc->regs + DMA_TLVL_REG);
|
||||
|
|
|
@ -656,9 +656,16 @@ static int rk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf,
|
|||
|
||||
dma_data = dma_map_single(nfc->dev, (void *)nfc->page_buf,
|
||||
mtd->writesize, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(nfc->dev, dma_data))
|
||||
return -ENOMEM;
|
||||
|
||||
dma_oob = dma_map_single(nfc->dev, nfc->oob_buf,
|
||||
ecc->steps * oob_step,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(nfc->dev, dma_oob)) {
|
||||
dma_unmap_single(nfc->dev, dma_data, mtd->writesize, DMA_TO_DEVICE);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
reinit_completion(&nfc->done);
|
||||
writel(INT_DMA, nfc->regs + nfc->cfg->int_en_off);
|
||||
|
@ -772,9 +779,17 @@ static int rk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *buf, int oob_on,
|
|||
dma_data = dma_map_single(nfc->dev, nfc->page_buf,
|
||||
mtd->writesize,
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(nfc->dev, dma_data))
|
||||
return -ENOMEM;
|
||||
|
||||
dma_oob = dma_map_single(nfc->dev, nfc->oob_buf,
|
||||
ecc->steps * oob_step,
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(nfc->dev, dma_oob)) {
|
||||
dma_unmap_single(nfc->dev, dma_data, mtd->writesize,
|
||||
DMA_FROM_DEVICE);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* The first blocks (4, 8 or 16 depending on the device)
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
#define AM_STATUS_ECC_MAX_CORRECTED (3 << 4)
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi-mem.h>
|
||||
|
||||
static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
|
||||
int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(reg,
|
||||
spinand->scratchbuf);
|
||||
|
@ -360,7 +360,7 @@ static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
|
|||
engine_conf->status = status;
|
||||
}
|
||||
|
||||
static int spinand_write_enable_op(struct spinand_device *spinand)
|
||||
int spinand_write_enable_op(struct spinand_device *spinand)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
|
||||
|
||||
|
@ -688,7 +688,10 @@ int spinand_write_page(struct spinand_device *spinand,
|
|||
SPINAND_WRITE_INITIAL_DELAY_US,
|
||||
SPINAND_WRITE_POLL_DELAY_US,
|
||||
&status);
|
||||
if (!ret && (status & STATUS_PROG_FAILED))
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (status & STATUS_PROG_FAILED)
|
||||
return -EIO;
|
||||
|
||||
return nand_ecc_finish_io_req(nand, (struct nand_page_io_req *)req);
|
||||
|
@ -1250,8 +1253,19 @@ static int spinand_id_detect(struct spinand_device *spinand)
|
|||
|
||||
static int spinand_manufacturer_init(struct spinand_device *spinand)
|
||||
{
|
||||
if (spinand->manufacturer->ops->init)
|
||||
return spinand->manufacturer->ops->init(spinand);
|
||||
int ret;
|
||||
|
||||
if (spinand->manufacturer->ops->init) {
|
||||
ret = spinand->manufacturer->ops->init(spinand);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (spinand->configure_chip) {
|
||||
ret = spinand->configure_chip(spinand);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1294,7 +1308,7 @@ spinand_select_op_variant(struct spinand_device *spinand,
|
|||
|
||||
nbytes -= op.data.nbytes;
|
||||
|
||||
op_duration_ns += spi_mem_calc_op_duration(&op);
|
||||
op_duration_ns += spi_mem_calc_op_duration(spinand->spimem, &op);
|
||||
}
|
||||
|
||||
if (!nbytes && op_duration_ns < best_op_duration_ns) {
|
||||
|
@ -1346,6 +1360,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
|
|||
spinand->flags = table[i].flags;
|
||||
spinand->id.len = 1 + table[i].devid.len;
|
||||
spinand->select_target = table[i].select_target;
|
||||
spinand->configure_chip = table[i].configure_chip;
|
||||
spinand->set_cont_read = table[i].set_cont_read;
|
||||
spinand->fact_otp = &table[i].fact_otp;
|
||||
spinand->user_otp = &table[i].user_otp;
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
(CFG_OTP_ENABLE | ESMT_F50L1G41LB_CFG_OTP_PROTECT)
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
#define SPINAND_MFR_FORESEE 0xCD
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
|
|
|
@ -24,36 +24,36 @@
|
|||
#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4)
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants_f,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(0, 0, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(0, 0, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants_1gq5,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants_2gq5,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
|
@ -533,6 +533,26 @@ static const struct spinand_info gigadevice_spinand_table[] = {
|
|||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
|
||||
gd5fxgq4uexxg_ecc_get_status)),
|
||||
SPINAND_INFO("GD5F1GM9UExxG",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x91, 0x01),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
|
||||
gd5fxgq4uexxg_ecc_get_status)),
|
||||
SPINAND_INFO("GD5F1GM9RExxG",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x81, 0x01),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
|
||||
gd5fxgq4uexxg_ecc_get_status)),
|
||||
};
|
||||
|
||||
static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
|
||||
|
|
|
@ -28,10 +28,10 @@ struct macronix_priv {
|
|||
};
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
|
|
|
@ -35,12 +35,12 @@
|
|||
(CFG_OTP_ENABLE | MICRON_MT29F2G01ABAGD_CFG_OTP_STATE)
|
||||
|
||||
static SPINAND_OP_VARIANTS(quadio_read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(x4_write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
|
@ -52,10 +52,10 @@ static SPINAND_OP_VARIANTS(x4_update_cache_variants,
|
|||
|
||||
/* Micron MT29F2G01AAAED Device */
|
||||
static SPINAND_OP_VARIANTS(x4_read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(x1_write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
#define SKYHIGH_CONFIG_PROTECT_EN BIT(1)
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
#define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4)
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_x4_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/mtd/spinand.h>
|
||||
#include <linux/units.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define SPINAND_MFR_WINBOND 0xEF
|
||||
|
||||
|
@ -18,17 +19,33 @@
|
|||
|
||||
#define W25N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4)
|
||||
|
||||
#define W25N0XJW_SR4 0xD0
|
||||
#define W25N0XJW_SR4_HS BIT(2)
|
||||
|
||||
#define W35N01JW_VCR_IO_MODE 0x00
|
||||
#define W35N01JW_VCR_IO_MODE_SINGLE_SDR 0xFF
|
||||
#define W35N01JW_VCR_IO_MODE_OCTAL_SDR 0xDF
|
||||
#define W35N01JW_VCR_IO_MODE_OCTAL_DDR_DS 0xE7
|
||||
#define W35N01JW_VCR_IO_MODE_OCTAL_DDR 0xC7
|
||||
#define W35N01JW_VCR_DUMMY_CLOCK_REG 0x01
|
||||
|
||||
/*
|
||||
* "X2" in the core is equivalent to "dual output" in the datasheets,
|
||||
* "X4" in the core is equivalent to "quad output" in the datasheets.
|
||||
* Quad and octal capable chips feature an absolute maximum frequency of 166MHz.
|
||||
*/
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_octal_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(0, 3, NULL, 0, 120 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(0, 2, NULL, 0, 105 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 20, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 16, NULL, 0, 162 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 12, NULL, 0, 124 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 8, NULL, 0, 86 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(0, 1, NULL, 0, 133 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_octal_variants,
|
||||
SPINAND_PROG_LOAD_1S_8S_8S_OP(true, 0, NULL, 0),
|
||||
|
@ -42,23 +59,25 @@ static SPINAND_OP_VARIANTS(update_cache_octal_variants,
|
|||
static SPINAND_OP_VARIANTS(read_cache_dual_quad_dtr_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(0, 8, NULL, 0, 80 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 104 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(0, 4, NULL, 0, 80 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 104 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 54 * HZ_PER_MHZ));
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
|
@ -230,6 +249,113 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int w25n0xjw_hs_cfg(struct spinand_device *spinand)
|
||||
{
|
||||
const struct spi_mem_op *op;
|
||||
bool hs;
|
||||
u8 sr4;
|
||||
int ret;
|
||||
|
||||
op = spinand->op_templates.read_cache;
|
||||
if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
|
||||
hs = false;
|
||||
else if (op->cmd.buswidth == 1 && op->addr.buswidth == 1 &&
|
||||
op->dummy.buswidth == 1 && op->data.buswidth == 1)
|
||||
hs = false;
|
||||
else if (!op->max_freq)
|
||||
hs = true;
|
||||
else
|
||||
hs = false;
|
||||
|
||||
ret = spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (hs)
|
||||
sr4 |= W25N0XJW_SR4_HS;
|
||||
else
|
||||
sr4 &= ~W25N0XJW_SR4_HS;
|
||||
|
||||
ret = spinand_write_reg_op(spinand, W25N0XJW_SR4, sr4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 val)
|
||||
{
|
||||
struct spi_mem_op op =
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x81, 1),
|
||||
SPI_MEM_OP_ADDR(3, reg, 1),
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_OUT(1, spinand->scratchbuf, 1));
|
||||
int ret;
|
||||
|
||||
*spinand->scratchbuf = val;
|
||||
|
||||
ret = spinand_write_enable_op(spinand);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = spi_mem_exec_op(spinand->spimem, &op);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Write VCR operation doesn't set the busy bit in SR, which means we
|
||||
* cannot perform a status poll. Minimum time of 50ns is needed to
|
||||
* complete the write.
|
||||
*/
|
||||
ndelay(50);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
|
||||
{
|
||||
const struct spi_mem_op *op;
|
||||
unsigned int dummy_cycles;
|
||||
bool dtr, single;
|
||||
u8 io_mode;
|
||||
int ret;
|
||||
|
||||
op = spinand->op_templates.read_cache;
|
||||
|
||||
single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1);
|
||||
dtr = (op->cmd.dtr || op->addr.dtr || op->data.dtr);
|
||||
if (single && !dtr)
|
||||
io_mode = W35N01JW_VCR_IO_MODE_SINGLE_SDR;
|
||||
else if (!single && !dtr)
|
||||
io_mode = W35N01JW_VCR_IO_MODE_OCTAL_SDR;
|
||||
else if (!single && dtr)
|
||||
io_mode = W35N01JW_VCR_IO_MODE_OCTAL_DDR;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE, io_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dummy_cycles = ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1);
|
||||
switch (dummy_cycles) {
|
||||
case 8:
|
||||
case 12:
|
||||
case 16:
|
||||
case 20:
|
||||
case 24:
|
||||
case 28:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_DUMMY_CLOCK_REG, dummy_cycles);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spinand_info winbond_spinand_table[] = {
|
||||
/* 512M-bit densities */
|
||||
SPINAND_INFO("W25N512GW", /* 1.8V */
|
||||
|
@ -268,7 +394,8 @@ static const struct spinand_info winbond_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)),
|
||||
SPINAND_INFO("W25N01KV", /* 3.3V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21),
|
||||
NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1),
|
||||
|
@ -286,7 +413,8 @@ static const struct spinand_info winbond_spinand_table[] = {
|
|||
&write_cache_octal_variants,
|
||||
&update_cache_octal_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL)),
|
||||
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
|
||||
SPINAND_INFO("W35N02JW", /* 1.8V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x22),
|
||||
NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 2, 1),
|
||||
|
@ -295,7 +423,8 @@ static const struct spinand_info winbond_spinand_table[] = {
|
|||
&write_cache_octal_variants,
|
||||
&update_cache_octal_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL)),
|
||||
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
|
||||
SPINAND_INFO("W35N04JW", /* 1.8V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x23),
|
||||
NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 4, 1),
|
||||
|
@ -304,7 +433,8 @@ static const struct spinand_info winbond_spinand_table[] = {
|
|||
&write_cache_octal_variants,
|
||||
&update_cache_octal_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL)),
|
||||
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
|
||||
/* 2G-bit densities */
|
||||
SPINAND_INFO("W25M02GV", /* 2x1G-bit 3.3V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21),
|
||||
|
@ -324,7 +454,8 @@ static const struct spinand_info winbond_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)),
|
||||
SPINAND_INFO("W25N02KV", /* 3.3V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
#define XT26XXXD_STATUS_ECC_UNCOR_ERROR (2)
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
|
|
|
@ -228,6 +228,25 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
|
|||
return BLOCK_NIL;
|
||||
}
|
||||
|
||||
static noinline_for_stack void NFTL_move_block(struct mtd_info *mtd, loff_t src, loff_t dst)
|
||||
{
|
||||
unsigned char movebuf[512];
|
||||
struct nftl_oob oob;
|
||||
size_t retlen;
|
||||
int ret;
|
||||
|
||||
ret = mtd_read(mtd, src, 512, &retlen, movebuf);
|
||||
if (ret < 0 && !mtd_is_bitflip(ret)) {
|
||||
ret = mtd_read(mtd, src, 512, &retlen, movebuf);
|
||||
if (ret != -EIO)
|
||||
printk("Error went away on retry.\n");
|
||||
}
|
||||
memset(&oob, 0xff, sizeof(struct nftl_oob));
|
||||
oob.b.Status = oob.b.Status1 = SECTOR_USED;
|
||||
|
||||
nftl_write(mtd, dst, 512, &retlen, movebuf, (char *)&oob);
|
||||
}
|
||||
|
||||
static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
|
||||
{
|
||||
struct mtd_info *mtd = nftl->mbd.mtd;
|
||||
|
@ -389,9 +408,6 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
|||
*/
|
||||
pr_debug("Folding chain %d into unit %d\n", thisVUC, targetEUN);
|
||||
for (block = 0; block < nftl->EraseSize / 512 ; block++) {
|
||||
unsigned char movebuf[512];
|
||||
int ret;
|
||||
|
||||
/* If it's in the target EUN already, or if it's pending write, do nothing */
|
||||
if (BlockMap[block] == targetEUN ||
|
||||
(pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) {
|
||||
|
@ -403,25 +419,8 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
|||
if (BlockMap[block] == BLOCK_NIL)
|
||||
continue;
|
||||
|
||||
ret = mtd_read(mtd,
|
||||
(nftl->EraseSize * BlockMap[block]) + (block * 512),
|
||||
512,
|
||||
&retlen,
|
||||
movebuf);
|
||||
if (ret < 0 && !mtd_is_bitflip(ret)) {
|
||||
ret = mtd_read(mtd,
|
||||
(nftl->EraseSize * BlockMap[block]) + (block * 512),
|
||||
512,
|
||||
&retlen,
|
||||
movebuf);
|
||||
if (ret != -EIO)
|
||||
printk("Error went away on retry.\n");
|
||||
}
|
||||
memset(&oob, 0xff, sizeof(struct nftl_oob));
|
||||
oob.b.Status = oob.b.Status1 = SECTOR_USED;
|
||||
|
||||
nftl_write(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
|
||||
(block * 512), 512, &retlen, movebuf, (char *)&oob);
|
||||
NFTL_move_block(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
|
||||
(nftl->EraseSize * targetEUN) + (block * 512));
|
||||
}
|
||||
|
||||
/* add the header so that it is now a valid chain */
|
||||
|
|
|
@ -189,7 +189,7 @@ static int mt25qu512a_post_bfpt_fixup(struct spi_nor *nor,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups mt25qu512a_fixups = {
|
||||
static const struct spi_nor_fixups mt25qu512a_fixups = {
|
||||
.post_bfpt = mt25qu512a_post_bfpt_fixup,
|
||||
};
|
||||
|
||||
|
@ -225,15 +225,15 @@ static int st_nor_two_die_late_init(struct spi_nor *nor)
|
|||
return spi_nor_set_4byte_addr_mode(nor, true);
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups n25q00_fixups = {
|
||||
static const struct spi_nor_fixups n25q00_fixups = {
|
||||
.late_init = st_nor_four_die_late_init,
|
||||
};
|
||||
|
||||
static struct spi_nor_fixups mt25q01_fixups = {
|
||||
static const struct spi_nor_fixups mt25q01_fixups = {
|
||||
.late_init = st_nor_two_die_late_init,
|
||||
};
|
||||
|
||||
static struct spi_nor_fixups mt25q02_fixups = {
|
||||
static const struct spi_nor_fixups mt25q02_fixups = {
|
||||
.late_init = st_nor_four_die_late_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
|
||||
#define SPINOR_OP_CLPEF 0x82 /* Clear program/erase failure flags */
|
||||
#define SPINOR_OP_CYPRESS_EX4B 0xB8 /* Exit 4-byte address mode */
|
||||
#define SPINOR_OP_CYPRESS_DIE_ERASE 0x61 /* Chip (die) erase */
|
||||
#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
|
||||
#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
|
||||
|
@ -58,6 +59,13 @@
|
|||
SPI_MEM_OP_DUMMY(ndummy, 0), \
|
||||
SPI_MEM_OP_DATA_IN(1, buf, 0))
|
||||
|
||||
#define CYPRESS_NOR_EN4B_EX4B_OP(enable) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(enable ? SPINOR_OP_EN4B : \
|
||||
SPINOR_OP_CYPRESS_EX4B, 0), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPANSION_OP(opcode) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
|
@ -356,6 +364,20 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cypress_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
|
||||
{
|
||||
int ret;
|
||||
struct spi_mem_op op = CYPRESS_NOR_EN4B_EX4B_OP(enable);
|
||||
|
||||
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
|
||||
|
||||
ret = spi_mem_exec_op(nor->spimem, &op);
|
||||
if (ret)
|
||||
dev_dbg(nor->dev, "error %d setting 4-byte mode\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cypress_nor_determine_addr_mode_by_sr1() - Determine current address mode
|
||||
* (3 or 4-byte) by querying status
|
||||
|
@ -526,6 +548,9 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor,
|
|||
struct spi_mem_op op;
|
||||
int ret;
|
||||
|
||||
/* Assign 4-byte address mode method that is not determined in BFPT */
|
||||
nor->params->set_4byte_addr_mode = cypress_nor_set_4byte_addr_mode;
|
||||
|
||||
ret = cypress_nor_set_addr_mode_nbytes(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -578,7 +603,7 @@ static int s25fs256t_late_init(struct spi_nor *nor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups s25fs256t_fixups = {
|
||||
static const struct spi_nor_fixups s25fs256t_fixups = {
|
||||
.post_bfpt = s25fs256t_post_bfpt_fixup,
|
||||
.post_sfdp = s25fs256t_post_sfdp_fixup,
|
||||
.late_init = s25fs256t_late_init,
|
||||
|
@ -591,6 +616,9 @@ s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
|
|||
{
|
||||
int ret;
|
||||
|
||||
/* Assign 4-byte address mode method that is not determined in BFPT */
|
||||
nor->params->set_4byte_addr_mode = cypress_nor_set_4byte_addr_mode;
|
||||
|
||||
ret = cypress_nor_set_addr_mode_nbytes(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -650,7 +678,7 @@ static int s25hx_t_late_init(struct spi_nor *nor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups s25hx_t_fixups = {
|
||||
static const struct spi_nor_fixups s25hx_t_fixups = {
|
||||
.post_bfpt = s25hx_t_post_bfpt_fixup,
|
||||
.post_sfdp = s25hx_t_post_sfdp_fixup,
|
||||
.late_init = s25hx_t_late_init,
|
||||
|
@ -718,6 +746,9 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor,
|
|||
const struct sfdp_parameter_header *bfpt_header,
|
||||
const struct sfdp_bfpt *bfpt)
|
||||
{
|
||||
/* Assign 4-byte address mode method that is not determined in BFPT */
|
||||
nor->params->set_4byte_addr_mode = cypress_nor_set_4byte_addr_mode;
|
||||
|
||||
return cypress_nor_set_addr_mode_nbytes(nor);
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,6 @@ static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)
|
|||
static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs,
|
||||
u64 *len)
|
||||
{
|
||||
struct mtd_info *mtd = &nor->mtd;
|
||||
u64 min_prot_len;
|
||||
u8 mask = spi_nor_get_sr_bp_mask(nor);
|
||||
u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
|
||||
|
@ -77,13 +76,13 @@ static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs,
|
|||
min_prot_len = spi_nor_get_min_prot_length_sr(nor);
|
||||
*len = min_prot_len << (bp - 1);
|
||||
|
||||
if (*len > mtd->size)
|
||||
*len = mtd->size;
|
||||
if (*len > nor->params->size)
|
||||
*len = nor->params->size;
|
||||
|
||||
if (nor->flags & SNOR_F_HAS_SR_TB && sr & tb_mask)
|
||||
*ofs = 0;
|
||||
else
|
||||
*ofs = mtd->size - *len;
|
||||
*ofs = nor->params->size - *len;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -158,7 +157,6 @@ static bool spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, u64 len,
|
|||
*/
|
||||
static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
||||
{
|
||||
struct mtd_info *mtd = &nor->mtd;
|
||||
u64 min_prot_len;
|
||||
int ret, status_old, status_new;
|
||||
u8 mask = spi_nor_get_sr_bp_mask(nor);
|
||||
|
@ -183,7 +181,7 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
can_be_bottom = false;
|
||||
|
||||
/* If anything above us is unlocked, we can't use 'top' protection */
|
||||
if (!spi_nor_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
|
||||
if (!spi_nor_is_locked_sr(nor, ofs + len, nor->params->size - (ofs + len),
|
||||
status_old))
|
||||
can_be_top = false;
|
||||
|
||||
|
@ -195,11 +193,11 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
|
||||
/* lock_len: length of region that should end up locked */
|
||||
if (use_top)
|
||||
lock_len = mtd->size - ofs;
|
||||
lock_len = nor->params->size - ofs;
|
||||
else
|
||||
lock_len = ofs + len;
|
||||
|
||||
if (lock_len == mtd->size) {
|
||||
if (lock_len == nor->params->size) {
|
||||
val = mask;
|
||||
} else {
|
||||
min_prot_len = spi_nor_get_min_prot_length_sr(nor);
|
||||
|
@ -248,7 +246,6 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
*/
|
||||
static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
|
||||
{
|
||||
struct mtd_info *mtd = &nor->mtd;
|
||||
u64 min_prot_len;
|
||||
int ret, status_old, status_new;
|
||||
u8 mask = spi_nor_get_sr_bp_mask(nor);
|
||||
|
@ -273,7 +270,7 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
can_be_top = false;
|
||||
|
||||
/* If anything above us is locked, we can't use 'bottom' protection */
|
||||
if (!spi_nor_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
|
||||
if (!spi_nor_is_unlocked_sr(nor, ofs + len, nor->params->size - (ofs + len),
|
||||
status_old))
|
||||
can_be_bottom = false;
|
||||
|
||||
|
@ -285,7 +282,7 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
|
|||
|
||||
/* lock_len: length of region that should remain locked */
|
||||
if (use_top)
|
||||
lock_len = mtd->size - (ofs + len);
|
||||
lock_len = nor->params->size - (ofs + len);
|
||||
else
|
||||
lock_len = ofs;
|
||||
|
||||
|
|
|
@ -586,14 +586,26 @@ EXPORT_SYMBOL_GPL(spi_mem_adjust_op_freq);
|
|||
* accurate, all these combinations should be rated (eg. with a time estimate)
|
||||
* and the best pick should be taken based on these calculations.
|
||||
*
|
||||
* Returns a ns estimate for the time this op would take.
|
||||
* Returns a ns estimate for the time this op would take, except if no
|
||||
* frequency limit has been set, in this case we return the number of
|
||||
* cycles nevertheless to allow callers to distinguish which operation
|
||||
* would be the fastest at iso-frequency.
|
||||
*/
|
||||
u64 spi_mem_calc_op_duration(struct spi_mem_op *op)
|
||||
u64 spi_mem_calc_op_duration(struct spi_mem *mem, struct spi_mem_op *op)
|
||||
{
|
||||
u64 ncycles = 0;
|
||||
u32 ns_per_cycles;
|
||||
u64 ps_per_cycles, duration;
|
||||
|
||||
spi_mem_adjust_op_freq(mem, op);
|
||||
|
||||
if (op->max_freq) {
|
||||
ps_per_cycles = 1000000000000ULL;
|
||||
do_div(ps_per_cycles, op->max_freq);
|
||||
} else {
|
||||
/* In this case, the unit is no longer a time unit */
|
||||
ps_per_cycles = 1;
|
||||
}
|
||||
|
||||
ns_per_cycles = 1000000000 / op->max_freq;
|
||||
ncycles += ((op->cmd.nbytes * 8) / op->cmd.buswidth) / (op->cmd.dtr ? 2 : 1);
|
||||
ncycles += ((op->addr.nbytes * 8) / op->addr.buswidth) / (op->addr.dtr ? 2 : 1);
|
||||
|
||||
|
@ -603,7 +615,12 @@ u64 spi_mem_calc_op_duration(struct spi_mem_op *op)
|
|||
|
||||
ncycles += ((op->data.nbytes * 8) / op->data.buswidth) / (op->data.dtr ? 2 : 1);
|
||||
|
||||
return ncycles * ns_per_cycles;
|
||||
/* Derive the duration in ps */
|
||||
duration = ncycles * ps_per_cycles;
|
||||
/* Convert into ns */
|
||||
do_div(duration, 1000);
|
||||
|
||||
return duration;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration);
|
||||
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
#ifndef __LINUX_MTD_MAP_H__
|
||||
#define __LINUX_MTD_MAP_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <asm/barrier.h>
|
||||
|
||||
struct device_node;
|
||||
struct module;
|
||||
|
||||
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
|
||||
#define map_bankwidth(map) 1
|
||||
|
@ -188,6 +188,7 @@ typedef union {
|
|||
of living.
|
||||
*/
|
||||
|
||||
struct mtd_chip_driver;
|
||||
struct map_info {
|
||||
const char *name;
|
||||
unsigned long size;
|
||||
|
|
|
@ -62,30 +62,33 @@
|
|||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(addr, ndummy, buf, len, ...) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x03, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(__VA_ARGS__ + 0))
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x03, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x0d, 1), \
|
||||
|
@ -94,17 +97,19 @@
|
|||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x3d, 1), \
|
||||
|
@ -113,18 +118,19 @@
|
|||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(addr, ndummy, buf, len, ...) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 2), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 2), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(__VA_ARGS__ + 0))
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_2S_2S_OP(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_2S_2S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 2), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 2), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xbd, 1), \
|
||||
|
@ -133,17 +139,19 @@
|
|||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6d, 1), \
|
||||
|
@ -152,18 +160,19 @@
|
|||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(addr, ndummy, buf, len, ...) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 4), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 4), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(__VA_ARGS__ + 0))
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_4S_4S_OP(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_4S_4S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 4), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 4), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xed, 1), \
|
||||
|
@ -484,6 +493,7 @@ struct spinand_user_otp {
|
|||
* @op_variants.update_cache: variants of the update-cache operation
|
||||
* @select_target: function used to select a target/die. Required only for
|
||||
* multi-die chips
|
||||
* @configure_chip: Align the chip configuration with the core settings
|
||||
* @set_cont_read: enable/disable continuous cached reads
|
||||
* @fact_otp: SPI NAND factory OTP info.
|
||||
* @user_otp: SPI NAND user OTP info.
|
||||
|
@ -507,6 +517,7 @@ struct spinand_info {
|
|||
} op_variants;
|
||||
int (*select_target)(struct spinand_device *spinand,
|
||||
unsigned int target);
|
||||
int (*configure_chip)(struct spinand_device *spinand);
|
||||
int (*set_cont_read)(struct spinand_device *spinand,
|
||||
bool enable);
|
||||
struct spinand_fact_otp fact_otp;
|
||||
|
@ -539,6 +550,9 @@ struct spinand_info {
|
|||
#define SPINAND_SELECT_TARGET(__func) \
|
||||
.select_target = __func
|
||||
|
||||
#define SPINAND_CONFIGURE_CHIP(__configure_chip) \
|
||||
.configure_chip = __configure_chip
|
||||
|
||||
#define SPINAND_CONT_READ(__set_cont_read) \
|
||||
.set_cont_read = __set_cont_read
|
||||
|
||||
|
@ -607,6 +621,7 @@ struct spinand_dirmap {
|
|||
* passed in spi_mem_op be DMA-able, so we can't based the bufs on
|
||||
* the stack
|
||||
* @manufacturer: SPI NAND manufacturer information
|
||||
* @configure_chip: Align the chip configuration with the core settings
|
||||
* @cont_read_possible: Field filled by the core once the whole system
|
||||
* configuration is known to tell whether continuous reads are
|
||||
* suitable to use or not in general with this chip/configuration.
|
||||
|
@ -647,6 +662,7 @@ struct spinand_device {
|
|||
const struct spinand_manufacturer *manufacturer;
|
||||
void *priv;
|
||||
|
||||
int (*configure_chip)(struct spinand_device *spinand);
|
||||
bool cont_read_possible;
|
||||
int (*set_cont_read)(struct spinand_device *spinand,
|
||||
bool enable);
|
||||
|
@ -723,7 +739,9 @@ int spinand_match_and_init(struct spinand_device *spinand,
|
|||
enum spinand_readid_method rdid_method);
|
||||
|
||||
int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
|
||||
int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val);
|
||||
int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val);
|
||||
int spinand_write_enable_op(struct spinand_device *spinand);
|
||||
int spinand_select_target(struct spinand_device *spinand, unsigned int target);
|
||||
|
||||
int spinand_wait(struct spinand_device *spinand, unsigned long initial_delay_us,
|
||||
|
|
|
@ -424,7 +424,7 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
|
|||
|
||||
int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op);
|
||||
void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op);
|
||||
u64 spi_mem_calc_op_duration(struct spi_mem_op *op);
|
||||
u64 spi_mem_calc_op_duration(struct spi_mem *mem, struct spi_mem_op *op);
|
||||
|
||||
bool spi_mem_supports_op(struct spi_mem *mem,
|
||||
const struct spi_mem_op *op);
|
||||
|
|
Loading…
Add table
Reference in a new issue