mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:24:47 +01:00
* MTD
The ofpart parsing in physmap-core has been prioritized.
There has been a series of conversion to scoped for each OF child
loops.
* Bindings
The bulk of the changes consists in binding fixes/updates to restrict
the use of undefined properties, which was almost inefficient in the
current form because of the nesting of partition nodes and the lack of
compatible strings sometimes.
These changes are accompanied by YAML conversions and the addition of a
dma-coherent property in the cdns,hp-nfc driver.
* SPI NAND
The major feature this release is the support for octal DTR
modes (8D-8D-8D).
Support for Foresee F35SQB002G chips has been added.
Other changes are small misc fixes.
-----BEGIN PGP SIGNATURE-----
iQEzBAABCgAdFiEE9HuaYnbmDhq/XIDIJWrqGEe9VoQFAmmPXI4ACgkQJWrqGEe9
VoQKJgf/YgI8L684Hq8OejCZYCoChZpTTvMmqmZ0CgRaZ157jcYTY5Od46pUpfEs
uSuoXW6+cuxdGeeUtyb3u5uJduO8r7UMjYLBqtMRGjvtfN9EDdhqVQWnRfCr9PoR
MS4moQa14tEakeP/u6stsmGLpzPkgiygcdTCWS4LhNoJ0LgkLjfBusQm6P5uqc+a
m/XS4Mg8SPj7pGjinu5KsvKWKiez6k4ExXiLM9p0TX/8iacFhGBrzKqv6zMiNyfL
p5ZS3ZLv9d79sLKOPlycfNO9LOp6O6ufn+zmuHQpTHGdlPegiNCoF1fOB9XZxc4A
iK9Z7b3ko9ta0HdjzRYkG/eFtTL0dQ==
=hnfP
-----END PGP SIGNATURE-----
Merge tag 'mtd/for-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
Pull MTD updates from Miquel Raynal:
"MTD:
- prioritize ofpart in physmap-core probing
- conversions to scoped for each OF child loops
Bindings:
- The bulk of the changes consists of binding fixes/updates to
restrict the use of undefined properties, which was mostly
ineffective in the current form because of the nesting of partition
nodes and the lack of compatible strings
- YAML conversions and the addition of a dma-coherent property in the
cdns,hp-nfc driver
SPI NAND:
- support for octal DTR modes (8D-8D-8D)
- support for Foresee F35SQB002G chips
And small misc fixes"
* tag 'mtd/for-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (65 commits)
mtd: spi-nor: hisi-sfc: fix refcounting bug in hisi_spi_nor_register_all()
mtd: spinand: fix NULL pointer dereference in spinand_support_vendor_ops()
mtd: rawnand: pl353: Add message about ECC mode
mtd: rawnand: pl353: Fix software ECC support
mtd: spinand: winbond: Remove unneeded semicolon
dt-bindings: mtd: cdns,hp-nfc: Add dma-coherent property
mtd: spinand: Disable continuous read during probe
mtd: spinand: add Foresee F35SQB002G flash support
mtd: spinand: winbond: W35N octal DTR support
mtd: spinand: Add octal DTR support
mtd: spinand: Warn if using SSDR-only vendor commands in a non SSDR mode
mtd: spinand: Give the bus interface to the configuration helper
mtd: spinand: Propagate the bus interface across core helpers
mtd: spinand: Add support for setting a bus interface
mtd: spinand: Gather all the bus interface steps in one single function
mtd: spinand: winbond: Configure the IO mode after the dummy cycles
mtd: spinand: winbond: Rename IO_MODE register macro
mtd: spinand: winbond: Fix style
mtd: spinand: winbond: Register W35N vendor specific operation
mtd: spinand: winbond: Register W25N vendor specific operation
...
This commit is contained in:
commit
1b49e36325
60 changed files with 1292 additions and 608 deletions
|
|
@ -32,21 +32,13 @@ properties:
|
|||
|
||||
patternProperties:
|
||||
"^partitions(-boot[12]|-gp[14])?$":
|
||||
$ref: /schemas/mtd/partitions/partitions.yaml
|
||||
type: object
|
||||
additionalProperties: true
|
||||
|
||||
patternProperties:
|
||||
"^partition@[0-9a-f]+$":
|
||||
$ref: /schemas/mtd/partitions/partition.yaml
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: Must be multiple of 512 as it's converted
|
||||
internally from bytes to SECTOR_SIZE (512 bytes)
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: fixed-partitions
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ properties:
|
|||
items:
|
||||
- const: brcm,nand-iproc
|
||||
- const: brcm,brcmnand-v6.1
|
||||
- const: brcm,brcmnand
|
||||
- description: BCM63168 SoC-specific NAND controller
|
||||
items:
|
||||
- const: brcm,nand-bcm63168
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ properties:
|
|||
dmas:
|
||||
maxItems: 1
|
||||
|
||||
dma-coherent: true
|
||||
|
||||
iommus:
|
||||
maxItems: 1
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
* MTD SPI driver for Microchip 23K256 (and similar) serial SRAM
|
||||
|
||||
Required properties:
|
||||
- #address-cells, #size-cells : Must be present if the device has sub-nodes
|
||||
representing partitions.
|
||||
- compatible : Must be one of "microchip,mchp23k256" or "microchip,mchp23lcv1024"
|
||||
- reg : Chip-Select number
|
||||
- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at
|
||||
|
||||
Example:
|
||||
|
||||
spi-sram@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "microchip,mchp23k256";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <20000000>;
|
||||
};
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/microchip,mchp23k256.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Microchip 23K256 SPI SRAM
|
||||
|
||||
maintainers:
|
||||
- Richard Weinberger <richard@nod.at>
|
||||
|
||||
description:
|
||||
The Microchip 23K256 is a 256 Kbit (32 Kbyte) serial SRAM with an
|
||||
SPI interface,supporting clock frequencies up to 20 MHz. It features
|
||||
a 32-byte page size for writes and supports byte, page, and
|
||||
sequential access modes.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- microchip,mchp23k256
|
||||
- microchip,mchp23lcv1024
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- reg
|
||||
- compatible
|
||||
- spi-max-frequency
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sram@0 {
|
||||
compatible = "microchip,mchp23k256";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <20000000>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
@ -30,18 +30,14 @@ properties:
|
|||
deprecated: true
|
||||
|
||||
partitions:
|
||||
$ref: /schemas/mtd/partitions/partitions.yaml
|
||||
type: object
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
patternProperties:
|
||||
"@[0-9a-f]+$":
|
||||
$ref: partitions/partition.yaml
|
||||
deprecated: true
|
||||
|
||||
"^partition@[0-9a-f]+":
|
||||
$ref: partitions/partition.yaml
|
||||
"(^partition)?@[0-9a-f]+$":
|
||||
$ref: /schemas/mtd/partitions/partition.yaml#/$defs/partition-node
|
||||
deprecated: true
|
||||
|
||||
"^otp(-[0-9]+)?$":
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/mxic,multi-itfc-v009-nand-controller.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Macronix Raw NAND Controller
|
||||
|
||||
maintainers:
|
||||
- Mason Yang <masonccyang@mxic.com.tw>
|
||||
|
||||
description:
|
||||
The Macronix Multi-Interface Raw NAND Controller is a versatile flash
|
||||
memory controller for embedding in SoCs, capable of interfacing with
|
||||
various NAND devices. It requires dedicated clock inputs for core, data
|
||||
transmit, and delayed transmit paths along with register space and an
|
||||
interrupt line for operation.
|
||||
|
||||
allOf:
|
||||
- $ref: nand-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mxic,multi-itfc-v009-nand-controller
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ps
|
||||
- const: send
|
||||
- const: send_dly
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
nand-controller@43c30000 {
|
||||
compatible = "mxic,multi-itfc-v009-nand-controller";
|
||||
reg = <0x43c30000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <GIC_SPI 0x1d IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>;
|
||||
clock-names = "ps", "send", "send_dly";
|
||||
|
||||
nand@0 {
|
||||
reg = <0>;
|
||||
nand-ecc-mode = "soft";
|
||||
nand-ecc-algo = "bch";
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
Macronix Raw NAND Controller Device Tree Bindings
|
||||
-------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "mxic,multi-itfc-v009-nand-controller"
|
||||
- reg: should contain 1 entry for the registers
|
||||
- #address-cells: should be set to 1
|
||||
- #size-cells: should be set to 0
|
||||
- interrupts: interrupt line connected to this raw NAND controller
|
||||
- clock-names: should contain "ps", "send" and "send_dly"
|
||||
- clocks: should contain 3 phandles for the "ps", "send" and
|
||||
"send_dly" clocks
|
||||
|
||||
Children nodes:
|
||||
- children nodes represent the available NAND chips.
|
||||
|
||||
See Documentation/devicetree/bindings/mtd/nand-controller.yaml
|
||||
for more details on generic bindings.
|
||||
|
||||
Example:
|
||||
|
||||
nand: nand-controller@43c30000 {
|
||||
compatible = "mxic,multi-itfc-v009-nand-controller";
|
||||
reg = <0x43c30000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <GIC_SPI 0x1d IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>;
|
||||
clock-names = "send", "send_dly", "ps";
|
||||
|
||||
nand@0 {
|
||||
reg = <0>;
|
||||
nand-ecc-mode = "soft";
|
||||
nand-ecc-algo = "bch";
|
||||
};
|
||||
};
|
||||
|
|
@ -9,8 +9,6 @@ title: ARM Firmware Suite (AFS) Partitions
|
|||
maintainers:
|
||||
- Linus Walleij <linusw@kernel.org>
|
||||
|
||||
select: false
|
||||
|
||||
description: |
|
||||
The ARM Firmware Suite is a flash partitioning system found on the
|
||||
ARM reference designs: Integrator AP, Integrator CP, Versatile AB,
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/partitions/binman.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Binman entries
|
||||
|
||||
description: |
|
||||
This corresponds to a binman 'entry'. It is a single partition which holds
|
||||
data of a defined type.
|
||||
|
||||
Binman uses the type to indicate what data file / type to place in the
|
||||
partition. There are quite a number of binman-specific entry types, such as
|
||||
section, fill and files, to be added later.
|
||||
|
||||
maintainers:
|
||||
- Simon Glass <sjg@chromium.org>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/mtd/partitions/partition.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- u-boot # u-boot.bin from U-Boot project
|
||||
- tfa-bl31 # bl31.bin or bl31.elf from TF-A project
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@100000 {
|
||||
compatible = "u-boot";
|
||||
reg = <0x100000 0xf00000>;
|
||||
align-size = <0x1000>;
|
||||
align-end = <0x10000>;
|
||||
};
|
||||
|
||||
partition@200000 {
|
||||
compatible = "tfa-bl31";
|
||||
reg = <0x200000 0x100000>;
|
||||
align = <0x4000>;
|
||||
};
|
||||
};
|
||||
|
|
@ -17,8 +17,6 @@ description: |
|
|||
maintainers:
|
||||
- Rafał Miłecki <rafal@milecki.pl>
|
||||
|
||||
select: false
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: brcm,bcm4908-partitions
|
||||
|
|
@ -31,11 +29,7 @@ properties:
|
|||
|
||||
patternProperties:
|
||||
"^partition@[0-9a-f]+$":
|
||||
$ref: partition.yaml#
|
||||
properties:
|
||||
compatible:
|
||||
const: brcm,bcm4908-firmware
|
||||
unevaluatedProperties: false
|
||||
$ref: partition.yaml#/$defs/partition-node
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
|
|
|
|||
|
|
@ -35,8 +35,6 @@ description: |
|
|||
maintainers:
|
||||
- Rafał Miłecki <rafal@milecki.pl>
|
||||
|
||||
select: false
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: brcm,bcm947xx-cfe-partitions
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
Broadcom BCM963XX ImageTag Partition Container
|
||||
==============================================
|
||||
|
||||
Some Broadcom BCM63XX SoC based devices contain additional, non discoverable
|
||||
partitions or non standard bootloader partition sizes. For these a mixed layout
|
||||
needs to be used with an explicit firmware partition.
|
||||
|
||||
The BCM963XX ImageTag is a simple firmware header describing the offsets and
|
||||
sizes of the rootfs and kernel parts contained in the firmware.
|
||||
|
||||
Required properties:
|
||||
- compatible : must be "brcm,bcm963xx-imagetag"
|
||||
|
||||
Example:
|
||||
|
||||
flash@1e000000 {
|
||||
compatible = "cfi-flash";
|
||||
reg = <0x1e000000 0x2000000>;
|
||||
bank-width = <2>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
cfe@0 {
|
||||
reg = <0x0 0x10000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
firmware@10000 {
|
||||
reg = <0x10000 0x7d0000>;
|
||||
compatible = "brcm,bcm963xx-imagetag";
|
||||
};
|
||||
|
||||
caldata@7e0000 {
|
||||
reg = <0x7e0000 0x10000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
nvram@7f0000 {
|
||||
reg = <0x7f0000 0x10000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
Broadcom TRX Container Partition
|
||||
================================
|
||||
|
||||
TRX is Broadcom's official firmware format for the BCM947xx boards. It's used by
|
||||
most of the vendors building devices based on Broadcom's BCM47xx SoCs and is
|
||||
supported by the CFE bootloader.
|
||||
|
||||
Design of the TRX format is very minimalistic. Its header contains
|
||||
identification fields, CRC32 checksum and the locations of embedded partitions.
|
||||
Its purpose is to store a few partitions in a format that can be distributed as
|
||||
a standalone file and written in a flash memory.
|
||||
|
||||
Container can hold up to 4 partitions. The first partition has to contain a
|
||||
device executable binary (e.g. a kernel) as it's what the CFE bootloader starts
|
||||
executing. Other partitions can be used for operating system purposes. This is
|
||||
useful for systems that keep kernel and rootfs separated.
|
||||
|
||||
TRX doesn't enforce any strict partition boundaries or size limits. All
|
||||
partitions have to be less than the 4GiB max size limit.
|
||||
|
||||
There are two existing/known TRX variants:
|
||||
1) v1 which contains 3 partitions
|
||||
2) v2 which contains 4 partitions
|
||||
|
||||
There aren't separated compatible bindings for them as version can be trivialy
|
||||
detected by a software parsing TRX header.
|
||||
|
||||
Required properties:
|
||||
- compatible : (required) must be "brcm,trx"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- brcm,trx-magic: TRX magic, if it is different from the default magic
|
||||
0x30524448 as a u32.
|
||||
|
||||
Example:
|
||||
|
||||
flash@0 {
|
||||
partitions {
|
||||
compatible = "brcm,trx";
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/partitions/brcm,trx.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom TRX Container Partition
|
||||
|
||||
maintainers:
|
||||
- Hauke Mehrtens <hauke@hauke-m.de>
|
||||
- Rafał Miłecki <rafal@milecki.pl>
|
||||
|
||||
description: >
|
||||
TRX is Broadcom's official firmware format for the BCM947xx boards. It's used by
|
||||
most of the vendors building devices based on Broadcom's BCM47xx SoCs and is
|
||||
supported by the CFE bootloader.
|
||||
|
||||
Design of the TRX format is very minimalistic. Its header contains
|
||||
identification fields, CRC32 checksum and the locations of embedded partitions.
|
||||
Its purpose is to store a few partitions in a format that can be distributed as
|
||||
a standalone file and written in a flash memory.
|
||||
|
||||
Container can hold up to 4 partitions. The first partition has to contain a
|
||||
device executable binary (e.g. a kernel) as it's what the CFE bootloader starts
|
||||
executing. Other partitions can be used for operating system purposes. This is
|
||||
useful for systems that keep kernel and rootfs separated.
|
||||
|
||||
TRX doesn't enforce any strict partition boundaries or size limits. All
|
||||
partitions have to be less than the 4GiB max size limit.
|
||||
|
||||
There are two existing/known TRX variants:
|
||||
1) v1 which contains 3 partitions
|
||||
2) v2 which contains 4 partitions
|
||||
|
||||
There aren't separated compatible bindings for them as version can be trivially
|
||||
detected by a software parsing TRX header.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: linksys,ns-firmware
|
||||
- const: brcm,trx
|
||||
- const: brcm,trx
|
||||
|
||||
brcm,trx-magic:
|
||||
description: TRX magic, if it is different from the default magic.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 0x30524448
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
allOf:
|
||||
- $ref: partition.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
flash {
|
||||
partitions {
|
||||
compatible = "brcm,trx";
|
||||
};
|
||||
};
|
||||
|
|
@ -25,47 +25,25 @@ properties:
|
|||
- const: sercomm,sc-partitions
|
||||
- const: fixed-partitions
|
||||
|
||||
"#address-cells": true
|
||||
"#address-cells":
|
||||
enum: [ 1, 2 ]
|
||||
|
||||
"#size-cells": true
|
||||
|
||||
compression:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description: |
|
||||
Compression algorithm used to store the data in this partition, chosen
|
||||
from a list of well-known algorithms.
|
||||
|
||||
The contents are compressed using this algorithm.
|
||||
|
||||
enum:
|
||||
- none
|
||||
- bzip2
|
||||
- gzip
|
||||
- lzop
|
||||
- lz4
|
||||
- lzma
|
||||
- xz
|
||||
- zstd
|
||||
"#size-cells":
|
||||
enum: [ 1, 2 ]
|
||||
|
||||
patternProperties:
|
||||
"@[0-9a-f]+$":
|
||||
$ref: partition.yaml#
|
||||
|
||||
properties:
|
||||
sercomm,scpart-id:
|
||||
description: Partition id in Sercomm partition map. Mtd parser
|
||||
uses this id to find a record in the partition map containing
|
||||
offset and size of the current partition. The values from
|
||||
partition map overrides partition offset and size defined in
|
||||
reg property of the dts. Frequently these values are the same,
|
||||
but may differ if device has bad eraseblocks on a flash.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
$ref: partition.yaml#/$defs/partition-node
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
additionalProperties: true
|
||||
# fixed-partitions can be nested
|
||||
allOf:
|
||||
- $ref: partition.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
@ -141,7 +119,6 @@ examples:
|
|||
compatible = "fixed-partitions";
|
||||
label = "calibration";
|
||||
reg = <0xf00000 0x100000>;
|
||||
ranges = <0 0xf00000 0x100000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@ description: |
|
|||
maintainers:
|
||||
- Rafał Miłecki <rafal@milecki.pl>
|
||||
|
||||
select: false
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: linksys,ns-partitions
|
||||
|
|
@ -32,13 +30,7 @@ properties:
|
|||
|
||||
patternProperties:
|
||||
"^partition@[0-9a-f]+$":
|
||||
$ref: partition.yaml#
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: linksys,ns-firmware
|
||||
- const: brcm,trx
|
||||
unevaluatedProperties: false
|
||||
$ref: partition.yaml#/$defs/partition-node
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
|
|
|
|||
|
|
@ -108,17 +108,59 @@ properties:
|
|||
with the padding bytes, so may grow. If ‘align-end’ is not provided,
|
||||
no alignment is performed.
|
||||
|
||||
compression:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description: |
|
||||
Compression algorithm used to store the data in this partition, chosen
|
||||
from a list of well-known algorithms.
|
||||
|
||||
The contents are compressed using this algorithm.
|
||||
|
||||
enum:
|
||||
- none
|
||||
- bzip2
|
||||
- gzip
|
||||
- lzop
|
||||
- lz4
|
||||
- lzma
|
||||
- xz
|
||||
- zstd
|
||||
|
||||
sercomm,scpart-id:
|
||||
description: Partition id in Sercomm partition map. Mtd parser
|
||||
uses this id to find a record in the partition map containing
|
||||
offset and size of the current partition. The values from
|
||||
partition map overrides partition offset and size defined in
|
||||
reg property of the dts. Frequently these values are the same,
|
||||
but may differ if device has bad eraseblocks on a flash.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
nvmem-layout:
|
||||
$ref: /schemas/nvmem/layouts/nvmem-layout.yaml
|
||||
|
||||
if:
|
||||
not:
|
||||
required: [ reg ]
|
||||
then:
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: '^partition-.*$'
|
||||
pattern: '^partitions?(-.+)?$'
|
||||
|
||||
# This is a generic file other binding inherit from and extend
|
||||
additionalProperties: true
|
||||
|
||||
$defs:
|
||||
partition-node:
|
||||
type: object
|
||||
if:
|
||||
not:
|
||||
required: [ compatible ]
|
||||
then:
|
||||
$ref: '#'
|
||||
unevaluatedProperties: false
|
||||
else:
|
||||
$ref: '#'
|
||||
|
||||
examples:
|
||||
- |
|
||||
partitions {
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/partitions/partitions.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Partitions
|
||||
|
||||
description: |
|
||||
This binding is generic and describes the content of the partitions container
|
||||
node. All partition parsers must be referenced here.
|
||||
|
||||
maintainers:
|
||||
- Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
|
||||
oneOf:
|
||||
- $ref: arm,arm-firmware-suite.yaml
|
||||
- $ref: brcm,bcm4908-partitions.yaml
|
||||
- $ref: brcm,bcm947xx-cfe-partitions.yaml
|
||||
- $ref: fixed-partitions.yaml
|
||||
- $ref: linksys,ns-partitions.yaml
|
||||
- $ref: qcom,smem-part.yaml
|
||||
- $ref: redboot-fis.yaml
|
||||
- $ref: tplink,safeloader-partitions.yaml
|
||||
|
||||
properties:
|
||||
compatible: true
|
||||
|
||||
'#address-cells':
|
||||
enum: [1, 2]
|
||||
|
||||
'#size-cells':
|
||||
enum: [1, 2]
|
||||
|
||||
patternProperties:
|
||||
"^partition(-.+|@[0-9a-f]+)$":
|
||||
$ref: partition.yaml
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
|
@ -28,10 +28,6 @@ properties:
|
|||
device. On a flash memory with 32KB eraseblocks, 0 means the first
|
||||
eraseblock at 0x00000000, 1 means the second eraseblock at 0x00008000 and so on.
|
||||
|
||||
'#address-cells': false
|
||||
|
||||
'#size-cells': false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- fis-index-block
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/partitions/seama.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Seattle Image Partitions
|
||||
|
||||
description: The SEAttle iMAge (SEAMA) partition is a type of partition
|
||||
used for NAND flash devices. This type of flash image is found in some
|
||||
D-Link routers such as DIR-645, DIR-842, DIR-859, DIR-860L, DIR-885L,
|
||||
DIR890L and DCH-M225, as well as in WD and NEC routers on the ath79
|
||||
(MIPS), Broadcom BCM53xx, and RAMIPS platforms. This partition type
|
||||
does not have children defined in the device tree, they need to be
|
||||
detected by software.
|
||||
|
||||
allOf:
|
||||
- $ref: partition.yaml#
|
||||
|
||||
maintainers:
|
||||
- Linus Walleij <linusw@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: seama
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
compatible = "seama";
|
||||
reg = <0x0 0x800000>;
|
||||
label = "firmware";
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/partitions/simple-partition.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Simple partition types
|
||||
|
||||
description:
|
||||
Simple partition types which only define a "compatible" value and no custom
|
||||
properties.
|
||||
|
||||
maintainers:
|
||||
- Rafał Miłecki <rafal@milecki.pl>
|
||||
- Simon Glass <sjg@chromium.org>
|
||||
|
||||
allOf:
|
||||
- $ref: partition.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: brcm,bcm4908-firmware
|
||||
description:
|
||||
Broadcom BCM4908 CFE bootloader firmware partition
|
||||
|
||||
- const: brcm,bcm963xx-imagetag
|
||||
description:
|
||||
The BCM963XX ImageTag is a simple firmware header describing the
|
||||
offsets and sizes of the rootfs and kernel parts contained in the
|
||||
firmware.
|
||||
|
||||
- const: seama
|
||||
description:
|
||||
The SEAttle iMAge (SEAMA) partition is a type of partition used for
|
||||
NAND flash devices. This type of flash image is found in some D-Link
|
||||
routers such as DIR-645, DIR-842, DIR-859, DIR-860L, DIR-885L, DIR890L
|
||||
and DCH-M225, as well as in WD and NEC routers on the ath79 (MIPS),
|
||||
Broadcom BCM53xx, and RAMIPS platforms. This partition type does not
|
||||
have children defined in the device tree, they need to be detected by
|
||||
software.
|
||||
|
||||
- const: u-boot
|
||||
description: >
|
||||
u-boot.bin from U-Boot project.
|
||||
|
||||
This corresponds to a binman 'entry'. It is a single partition which holds
|
||||
data of a defined type.
|
||||
|
||||
Binman uses the type to indicate what data file / type to place in the
|
||||
partition. There are quite a number of binman-specific entry types, such as
|
||||
section, fill and files, to be added later.
|
||||
|
||||
- const: tfa-bl31
|
||||
description: >
|
||||
bl31.bin or bl31.elf from TF-A project
|
||||
|
||||
This corresponds to a binman 'entry'. It is a single partition which holds
|
||||
data of a defined type.
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
|
@ -38,7 +38,7 @@ properties:
|
|||
|
||||
patternProperties:
|
||||
"^partition-.*$":
|
||||
$ref: partition.yaml#
|
||||
$ref: partition.yaml#/$defs/partition-node
|
||||
|
||||
required:
|
||||
- partitions-table-offset
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ properties:
|
|||
|
||||
patternProperties:
|
||||
"^partition-.*$":
|
||||
$ref: partition.yaml#
|
||||
$ref: partition.yaml#/$defs/partition-node
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
* SPEAr SMI
|
||||
|
||||
Required properties:
|
||||
- compatible : "st,spear600-smi"
|
||||
- reg : Address range of the mtd chip
|
||||
- #address-cells, #size-cells : Must be present if the device has sub-nodes
|
||||
representing partitions.
|
||||
- interrupts: Should contain the STMMAC interrupts
|
||||
- clock-rate : Functional clock rate of SMI in Hz
|
||||
|
||||
Optional properties:
|
||||
- st,smi-fast-mode : Flash supports read in fast mode
|
||||
|
||||
Example:
|
||||
|
||||
smi: flash@fc000000 {
|
||||
compatible = "st,spear600-smi";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0xfc000000 0x1000>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <12>;
|
||||
clock-rate = <50000000>; /* 50MHz */
|
||||
|
||||
flash@f8000000 {
|
||||
st,smi-fast-mode;
|
||||
...
|
||||
};
|
||||
};
|
||||
72
Documentation/devicetree/bindings/mtd/st,spear600-smi.yaml
Normal file
72
Documentation/devicetree/bindings/mtd/st,spear600-smi.yaml
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/st,spear600-smi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STMicroelectronics SPEAr600 Serial Memory Interface (SMI) Controller
|
||||
|
||||
maintainers:
|
||||
- Richard Weinberger <richard@nod.at>
|
||||
|
||||
description:
|
||||
The SPEAr600 Serial Memory Interface (SMI) is a dedicated serial flash
|
||||
controller supporting up to four chip selects for serial NOR flashes
|
||||
connected in parallel. The controller is memory-mapped and the attached
|
||||
flash devices appear in the CPU address space.The driver
|
||||
(drivers/mtd/devices/spear_smi.c) probes the attached flashes
|
||||
dynamically by sending commands (e.g., RDID) to each bank.
|
||||
Flash sub nodes describe the memory range and optional per-flash
|
||||
properties.
|
||||
|
||||
allOf:
|
||||
- $ref: mtd.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: st,spear600-smi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 1
|
||||
|
||||
clock-rate:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Functional clock rate of the SMI controller in Hz.
|
||||
|
||||
st,smi-fast-mode:
|
||||
type: boolean
|
||||
description: Indicates that the attached flash supports fast read mode.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clock-rate
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
flash@fc000000 {
|
||||
compatible = "st,spear600-smi";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0xfc000000 0x1000>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <12>;
|
||||
clock-rate = <50000000>; /* 50 MHz */
|
||||
|
||||
flash@f8000000 {
|
||||
reg = <0xfc000000 0x1000>;
|
||||
st,smi-fast-mode;
|
||||
};
|
||||
};
|
||||
...
|
||||
68
Documentation/devicetree/bindings/mtd/st,spi-fsm.yaml
Normal file
68
Documentation/devicetree/bindings/mtd/st,spi-fsm.yaml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/st,spi-fsm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STMicroelectronics SPI FSM Serial NOR Flash Controller
|
||||
|
||||
maintainers:
|
||||
- Angus Clark <angus.clark@st.com>
|
||||
|
||||
description:
|
||||
The STMicroelectronics Fast Sequence Mode (FSM) controller is a dedicated
|
||||
hardware accelerator integrated in older STiH4xx/STiDxxx set-top box SoCs
|
||||
(such as STiH407, STiH416, STiD127). It connects directly to a single
|
||||
external serial flash device used as the primary boot device. The FSM
|
||||
executes hard-coded or configurable instruction sequences in hardware,
|
||||
providing low-latency reads suitable for execute-in-place (XIP) boot
|
||||
and high read bandwidth.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: st,spi-fsm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reg-names:
|
||||
const: spi-fsm
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
st,syscfg:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: Phandle to the system configuration registers used for boot-device selection.
|
||||
|
||||
st,boot-device-reg:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Offset of the boot-device register within the st,syscfg node.
|
||||
|
||||
st,boot-device-spi:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Expected boot-device value when booting from this SPI controller.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- pinctrl-0
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
spifsm@fe902000 {
|
||||
compatible = "st,spi-fsm";
|
||||
reg = <0xfe902000 0x1000>;
|
||||
reg-names = "spi-fsm";
|
||||
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
|
||||
pinctrl-0 = <&pinctrl_fsm>;
|
||||
st,syscfg = <&syscfg_rear>;
|
||||
st,boot-device-reg = <0x958>;
|
||||
st,boot-device-spi = <0x1a>;
|
||||
};
|
||||
...
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
* ST-Microelectronics SPI FSM Serial (NOR) Flash Controller
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "st,spi-fsm"
|
||||
- reg : Contains register's location and length.
|
||||
- reg-names : Should contain the reg names "spi-fsm"
|
||||
- interrupts : The interrupt number
|
||||
- pinctrl-0 : Standard Pinctrl phandle (see: pinctrl/pinctrl-bindings.txt)
|
||||
|
||||
Optional properties:
|
||||
- st,syscfg : Phandle to boot-device system configuration registers
|
||||
- st,boot-device-reg : Address of the aforementioned boot-device register(s)
|
||||
- st,boot-device-spi : Expected boot-device value if booted via this device
|
||||
|
||||
Example:
|
||||
spifsm: spifsm@fe902000{
|
||||
compatible = "st,spi-fsm";
|
||||
reg = <0xfe902000 0x1000>;
|
||||
reg-names = "spi-fsm";
|
||||
pinctrl-0 = <&pinctrl_fsm>;
|
||||
st,syscfg = <&syscfg_rear>;
|
||||
st,boot-device-reg = <0x958>;
|
||||
st,boot-device-spi = <0x1a>;
|
||||
};
|
||||
|
||||
|
|
@ -24,7 +24,9 @@ properties:
|
|||
- description: AEMIF control registers.
|
||||
|
||||
partitions:
|
||||
$ref: /schemas/mtd/partitions/partitions.yaml
|
||||
type: object
|
||||
required:
|
||||
- compatible
|
||||
|
||||
ti,davinci-chipselect:
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ properties:
|
|||
|
||||
patternProperties:
|
||||
"@[0-9a-f]+$":
|
||||
$ref: /schemas/mtd/partitions/partition.yaml
|
||||
$ref: /schemas/mtd/partitions/partition.yaml#/$defs/partition-node
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/memory-controllers/ti,gpmc-child.yaml
|
||||
|
|
|
|||
|
|
@ -4445,11 +4445,6 @@ F: Documentation/filesystems/bfs.rst
|
|||
F: fs/bfs/
|
||||
F: include/uapi/linux/bfs_fs.h
|
||||
|
||||
BINMAN
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/mtd/partitions/binman*
|
||||
|
||||
BITMAP API
|
||||
M: Yury Norov <yury.norov@gmail.com>
|
||||
R: Rasmus Villemoes <linux@rasmusvillemoes.dk>
|
||||
|
|
|
|||
|
|
@ -1921,7 +1921,7 @@ static inline u32 jedec_read_mfr(struct map_info *map, uint32_t base,
|
|||
*/
|
||||
do {
|
||||
uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), map, cfi);
|
||||
mask = (1 << (cfi->device_type * 8)) - 1;
|
||||
mask = (1ULL << (cfi->device_type * 8)) - 1;
|
||||
if (ofs >= map->size)
|
||||
return 0;
|
||||
result = map_read(map, base + ofs);
|
||||
|
|
@ -1937,7 +1937,7 @@ static inline u32 jedec_read_id(struct map_info *map, uint32_t base,
|
|||
map_word result;
|
||||
unsigned long mask;
|
||||
u32 ofs = cfi_build_cmd_addr(1, map, cfi);
|
||||
mask = (1 << (cfi->device_type * 8)) -1;
|
||||
mask = (1ULL << (cfi->device_type * 8)) - 1;
|
||||
result = map_read(map, base + ofs);
|
||||
return result.x[0] & mask;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -770,6 +770,7 @@ static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev,
|
|||
|
||||
kref_init(&nvm->refcnt);
|
||||
mutex_init(&nvm->lock);
|
||||
nvm->nregions = nregions;
|
||||
|
||||
for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) {
|
||||
if (!invm->regions[i].name)
|
||||
|
|
@ -777,13 +778,15 @@ static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev,
|
|||
|
||||
char *name = kasprintf(GFP_KERNEL, "%s.%s",
|
||||
dev_name(&aux_dev->dev), invm->regions[i].name);
|
||||
if (!name)
|
||||
continue;
|
||||
if (!name) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
nvm->regions[n].name = name;
|
||||
nvm->regions[n].id = i;
|
||||
n++;
|
||||
}
|
||||
nvm->nregions = n; /* in case where kasprintf fail */
|
||||
|
||||
ret = devm_pm_runtime_enable(device);
|
||||
if (ret < 0) {
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ static const struct of_device_id of_flash_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, of_flash_match);
|
||||
|
||||
static const char * const of_default_part_probes[] = {
|
||||
"cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL
|
||||
"cmdlinepart", "ofpart", "ofoldpart", "RedBoot", NULL
|
||||
};
|
||||
|
||||
static const char * const *of_get_part_probes(struct platform_device *dev)
|
||||
|
|
|
|||
|
|
@ -2304,10 +2304,8 @@ atmel_hsmc_nand_controller_init(struct atmel_hsmc_nand_controller *nc)
|
|||
|
||||
nc->sram.pool = of_gen_pool_get(nc->base.dev->of_node,
|
||||
"atmel,nfc-sram", 0);
|
||||
if (!nc->sram.pool) {
|
||||
dev_err(nc->base.dev, "Missing SRAM\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!nc->sram.pool)
|
||||
return dev_err_probe(nc->base.dev, -EPROBE_DEFER, "Missing SRAM\n");
|
||||
|
||||
nc->sram.virt = (void __iomem *)gen_pool_dma_alloc(nc->sram.pool,
|
||||
ATMEL_NFC_SRAM_SIZE,
|
||||
|
|
|
|||
|
|
@ -3298,7 +3298,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
|
|||
{
|
||||
struct brcmnand_platform_data *pd = dev_get_platdata(&pdev->dev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *dn = dev->of_node, *child;
|
||||
struct device_node *dn = dev->of_node;
|
||||
struct brcmnand_controller *ctrl;
|
||||
struct brcmnand_host *host;
|
||||
struct resource *res;
|
||||
|
|
@ -3486,12 +3486,11 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
|
|||
}
|
||||
}
|
||||
|
||||
for_each_available_child_of_node(dn, child) {
|
||||
for_each_available_child_of_node_scoped(dn, child) {
|
||||
if (of_device_is_compatible(child, "brcm,nandcs")) {
|
||||
|
||||
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
|
||||
if (!host) {
|
||||
of_node_put(child);
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
|
@ -3509,10 +3508,9 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
|
|||
|
||||
ret = brcmnand_init_cs(host, NULL);
|
||||
if (ret) {
|
||||
if (ret == -EPROBE_DEFER) {
|
||||
of_node_put(child);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
goto err;
|
||||
}
|
||||
|
||||
devm_kfree(dev, host);
|
||||
continue; /* Try all chip-selects */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1066,7 +1066,7 @@ static int cadence_nand_cdma_send(struct cdns_nand_ctrl *cdns_ctrl,
|
|||
}
|
||||
|
||||
/* Send SDMA command and wait for finish. */
|
||||
static u32
|
||||
static int
|
||||
cadence_nand_cdma_send_and_wait(struct cdns_nand_ctrl *cdns_ctrl,
|
||||
u8 thread)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -115,7 +115,6 @@ static int denali_dt_probe(struct platform_device *pdev)
|
|||
struct denali_dt *dt;
|
||||
const struct denali_dt_data *data;
|
||||
struct denali_controller *denali;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
dt = devm_kzalloc(dev, sizeof(*dt), GFP_KERNEL);
|
||||
|
|
@ -192,12 +191,10 @@ static int denali_dt_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto out_assert_rst;
|
||||
|
||||
for_each_child_of_node(dev->of_node, np) {
|
||||
for_each_child_of_node_scoped(dev->of_node, np) {
|
||||
ret = denali_dt_chip_init(denali, np);
|
||||
if (ret) {
|
||||
of_node_put(np);
|
||||
if (ret)
|
||||
goto out_remove_denali;
|
||||
}
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, dt);
|
||||
|
|
|
|||
|
|
@ -438,7 +438,6 @@ static int ingenic_nand_init_chips(struct ingenic_nfc *nfc,
|
|||
struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np;
|
||||
int i = 0;
|
||||
int ret;
|
||||
int num_chips = of_get_child_count(dev->of_node);
|
||||
|
|
@ -449,11 +448,10 @@ static int ingenic_nand_init_chips(struct ingenic_nfc *nfc,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
for_each_child_of_node(dev->of_node, np) {
|
||||
for_each_child_of_node_scoped(dev->of_node, np) {
|
||||
ret = ingenic_nand_init_chip(pdev, nfc, np, i);
|
||||
if (ret) {
|
||||
ingenic_nand_cleanup_chips(nfc);
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -970,14 +970,18 @@ static int pl35x_nand_attach_chip(struct nand_chip *chip)
|
|||
|
||||
switch (chip->ecc.engine_type) {
|
||||
case NAND_ECC_ENGINE_TYPE_ON_DIE:
|
||||
dev_dbg(nfc->dev, "Using on-die ECC\n");
|
||||
/* Keep these legacy BBT descriptors for ON_DIE situations */
|
||||
chip->bbt_td = &bbt_main_descr;
|
||||
chip->bbt_md = &bbt_mirror_descr;
|
||||
fallthrough;
|
||||
case NAND_ECC_ENGINE_TYPE_NONE:
|
||||
case NAND_ECC_ENGINE_TYPE_SOFT:
|
||||
dev_dbg(nfc->dev, "Using software ECC (Hamming 1-bit/512B)\n");
|
||||
chip->ecc.write_page_raw = nand_monolithic_write_page_raw;
|
||||
break;
|
||||
case NAND_ECC_ENGINE_TYPE_ON_HOST:
|
||||
dev_dbg(nfc->dev, "Using hardware ECC\n");
|
||||
ret = pl35x_nand_init_hw_ecc_controller(nfc, chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -2206,16 +2206,14 @@ err:
|
|||
static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
|
||||
{
|
||||
struct device *dev = nandc->dev;
|
||||
struct device_node *dn = dev->of_node, *child;
|
||||
struct device_node *dn = dev->of_node;
|
||||
struct qcom_nand_host *host;
|
||||
int ret = -ENODEV;
|
||||
|
||||
for_each_available_child_of_node(dn, child) {
|
||||
for_each_available_child_of_node_scoped(dn, child) {
|
||||
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
|
||||
if (!host) {
|
||||
of_node_put(child);
|
||||
if (!host)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = qcom_nand_host_init_and_register(nandc, host, child);
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -29,12 +29,6 @@
|
|||
#include <linux/iopoll.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
/* non compile-time field get/prep */
|
||||
#undef field_get
|
||||
#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
|
||||
#undef field_prep
|
||||
#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))
|
||||
|
||||
#define NFC_REG_CTL 0x0000
|
||||
#define NFC_REG_ST 0x0004
|
||||
#define NFC_REG_INT 0x0008
|
||||
|
|
|
|||
|
|
@ -810,7 +810,6 @@ static int vf610_nfc_probe(struct platform_device *pdev)
|
|||
struct vf610_nfc *nfc;
|
||||
struct mtd_info *mtd;
|
||||
struct nand_chip *chip;
|
||||
struct device_node *child;
|
||||
int err;
|
||||
int irq;
|
||||
|
||||
|
|
@ -840,17 +839,16 @@ static int vf610_nfc_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(nfc->clk);
|
||||
}
|
||||
|
||||
nfc->variant = (enum vf610_nfc_variant)device_get_match_data(&pdev->dev);
|
||||
nfc->variant = (unsigned long)device_get_match_data(&pdev->dev);
|
||||
if (!nfc->variant)
|
||||
return -ENODEV;
|
||||
|
||||
for_each_available_child_of_node(nfc->dev->of_node, child) {
|
||||
for_each_available_child_of_node_scoped(nfc->dev->of_node, child) {
|
||||
if (of_device_is_compatible(child, "fsl,vf610-nfc-nandcs")) {
|
||||
|
||||
if (nand_get_flash_node(chip)) {
|
||||
dev_err(nfc->dev,
|
||||
"Only one NAND chip supported!\n");
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
spinand-objs := core.o otp.o
|
||||
spinand-objs += alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o
|
||||
spinand-objs += micron.o paragon.o skyhigh.o toshiba.o winbond.o xtx.o
|
||||
spinand-objs += alliancememory.o ato.o dosilicon.o esmt.o fmsh.o foresee.o gigadevice.o
|
||||
spinand-objs += macronix.o micron.o paragon.o skyhigh.o toshiba.o winbond.o xtx.o
|
||||
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
|
||||
|
|
|
|||
|
|
@ -20,10 +20,100 @@
|
|||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi-mem.h>
|
||||
|
||||
static struct spi_mem_op
|
||||
spinand_fill_reset_op(struct spinand_device *spinand)
|
||||
{
|
||||
return spinand->op_templates->reset;
|
||||
}
|
||||
|
||||
static struct spi_mem_op
|
||||
spinand_fill_readid_op(struct spinand_device *spinand,
|
||||
u8 naddr, u8 ndummy, void *buf, unsigned int len)
|
||||
{
|
||||
struct spi_mem_op op = spinand->op_templates->readid;
|
||||
|
||||
op.addr.nbytes = naddr;
|
||||
op.dummy.nbytes = ndummy;
|
||||
op.data.buf.in = buf;
|
||||
op.data.nbytes = len;
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
struct spi_mem_op
|
||||
spinand_fill_wr_en_op(struct spinand_device *spinand)
|
||||
{
|
||||
return spinand->op_templates->wr_en;
|
||||
}
|
||||
|
||||
static __maybe_unused struct spi_mem_op
|
||||
spinand_fill_wr_dis_op(struct spinand_device *spinand)
|
||||
{
|
||||
return spinand->op_templates->wr_dis;
|
||||
}
|
||||
|
||||
struct spi_mem_op
|
||||
spinand_fill_set_feature_op(struct spinand_device *spinand, u64 reg, const void *valptr)
|
||||
{
|
||||
struct spi_mem_op op = spinand->op_templates->set_feature;
|
||||
|
||||
if (op.cmd.dtr && op.cmd.buswidth == 8)
|
||||
reg |= reg << 8;
|
||||
|
||||
op.addr.val = reg;
|
||||
op.data.buf.out = valptr;
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
struct spi_mem_op
|
||||
spinand_fill_get_feature_op(struct spinand_device *spinand, u64 reg, void *valptr)
|
||||
{
|
||||
struct spi_mem_op op = spinand->op_templates->get_feature;
|
||||
|
||||
if (op.cmd.dtr && op.cmd.buswidth == 8)
|
||||
reg |= reg << 8;
|
||||
|
||||
op.addr.val = reg;
|
||||
op.data.buf.in = valptr;
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
static struct spi_mem_op
|
||||
spinand_fill_blk_erase_op(struct spinand_device *spinand, u64 addr)
|
||||
{
|
||||
struct spi_mem_op op = spinand->op_templates->blk_erase;
|
||||
|
||||
op.addr.val = addr;
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
static struct spi_mem_op
|
||||
spinand_fill_page_read_op(struct spinand_device *spinand, u64 addr)
|
||||
{
|
||||
struct spi_mem_op op = spinand->op_templates->page_read;
|
||||
|
||||
op.addr.val = addr;
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
struct spi_mem_op
|
||||
spinand_fill_prog_exec_op(struct spinand_device *spinand, u64 addr)
|
||||
{
|
||||
struct spi_mem_op op = spinand->op_templates->prog_exec;
|
||||
|
||||
op.addr.val = addr;
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
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);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, get_feature,
|
||||
reg, spinand->scratchbuf);
|
||||
int ret;
|
||||
|
||||
ret = spi_mem_exec_op(spinand->spimem, &op);
|
||||
|
|
@ -36,8 +126,8 @@ 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)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(reg,
|
||||
spinand->scratchbuf);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, set_feature,
|
||||
reg, spinand->scratchbuf);
|
||||
|
||||
*spinand->scratchbuf = val;
|
||||
return spi_mem_exec_op(spinand->spimem, &op);
|
||||
|
|
@ -177,18 +267,9 @@ static int spinand_init_cfg_cache(struct spinand_device *spinand)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int spinand_init_quad_enable(struct spinand_device *spinand)
|
||||
static int spinand_init_quad_enable(struct spinand_device *spinand,
|
||||
bool enable)
|
||||
{
|
||||
bool enable = false;
|
||||
|
||||
if (!(spinand->flags & SPINAND_HAS_QE_BIT))
|
||||
return 0;
|
||||
|
||||
if (spinand->op_templates.read_cache->data.buswidth == 4 ||
|
||||
spinand->op_templates.write_cache->data.buswidth == 4 ||
|
||||
spinand->op_templates.update_cache->data.buswidth == 4)
|
||||
enable = true;
|
||||
|
||||
return spinand_upd_cfg(spinand, CFG_QUAD_ENABLE,
|
||||
enable ? CFG_QUAD_ENABLE : 0);
|
||||
}
|
||||
|
|
@ -362,7 +443,7 @@ static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
|
|||
|
||||
int spinand_write_enable_op(struct spinand_device *spinand)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, wr_en);
|
||||
|
||||
return spi_mem_exec_op(spinand->spimem, &op);
|
||||
}
|
||||
|
|
@ -372,7 +453,7 @@ static int spinand_load_page_op(struct spinand_device *spinand,
|
|||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
unsigned int row = nanddev_pos_to_row(nand, &req->pos);
|
||||
struct spi_mem_op op = SPINAND_PAGE_READ_1S_1S_0_OP(row);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, page_read, row);
|
||||
|
||||
return spi_mem_exec_op(spinand->spimem, &op);
|
||||
}
|
||||
|
|
@ -527,7 +608,7 @@ static int spinand_program_op(struct spinand_device *spinand,
|
|||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
unsigned int row = nanddev_pos_to_row(nand, &req->pos);
|
||||
struct spi_mem_op op = SPINAND_PROG_EXEC_1S_1S_0_OP(row);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, prog_exec, row);
|
||||
|
||||
return spi_mem_exec_op(spinand->spimem, &op);
|
||||
}
|
||||
|
|
@ -537,7 +618,7 @@ static int spinand_erase_op(struct spinand_device *spinand,
|
|||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
unsigned int row = nanddev_pos_to_row(nand, pos);
|
||||
struct spi_mem_op op = SPINAND_BLK_ERASE_1S_1S_0_OP(row);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, blk_erase, row);
|
||||
|
||||
return spi_mem_exec_op(spinand->spimem, &op);
|
||||
}
|
||||
|
|
@ -557,8 +638,8 @@ static int spinand_erase_op(struct spinand_device *spinand,
|
|||
int spinand_wait(struct spinand_device *spinand, unsigned long initial_delay_us,
|
||||
unsigned long poll_delay_us, u8 *s)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(REG_STATUS,
|
||||
spinand->scratchbuf);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, get_feature,
|
||||
REG_STATUS, spinand->scratchbuf);
|
||||
u8 status;
|
||||
int ret;
|
||||
|
||||
|
|
@ -591,8 +672,8 @@ out:
|
|||
static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
|
||||
u8 ndummy, u8 *buf)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_READID_1S_1S_1S_OP(
|
||||
naddr, ndummy, spinand->scratchbuf, SPINAND_MAX_ID_LEN);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, readid,
|
||||
naddr, ndummy, spinand->scratchbuf, SPINAND_MAX_ID_LEN);
|
||||
int ret;
|
||||
|
||||
ret = spi_mem_exec_op(spinand->spimem, &op);
|
||||
|
|
@ -604,7 +685,7 @@ static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
|
|||
|
||||
static int spinand_reset_op(struct spinand_device *spinand)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_RESET_1S_0_0_OP;
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, reset);
|
||||
int ret;
|
||||
|
||||
ret = spi_mem_exec_op(spinand->spimem, &op);
|
||||
|
|
@ -859,6 +940,14 @@ static void spinand_cont_read_init(struct spinand_device *spinand)
|
|||
(engine_type == NAND_ECC_ENGINE_TYPE_ON_DIE ||
|
||||
engine_type == NAND_ECC_ENGINE_TYPE_NONE)) {
|
||||
spinand->cont_read_possible = true;
|
||||
|
||||
/*
|
||||
* Ensure continuous read is disabled on probe.
|
||||
* Some devices retain this state across soft reset,
|
||||
* which leaves the OOB area inaccessible and results
|
||||
* in false positive returns from spinand_isbad().
|
||||
*/
|
||||
spinand_cont_read_enable(spinand, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1154,7 +1243,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
|
|||
info.offset = plane << fls(nand->memorg.pagesize);
|
||||
|
||||
info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
|
||||
info.op_tmpl = *spinand->op_templates.update_cache;
|
||||
info.op_tmpl = *spinand->op_templates->update_cache;
|
||||
desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
|
||||
spinand->spimem, &info);
|
||||
if (IS_ERR(desc))
|
||||
|
|
@ -1162,7 +1251,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
|
|||
|
||||
spinand->dirmaps[plane].wdesc = desc;
|
||||
|
||||
info.op_tmpl = *spinand->op_templates.read_cache;
|
||||
info.op_tmpl = *spinand->op_templates->read_cache;
|
||||
desc = spinand_create_rdesc(spinand, &info);
|
||||
if (IS_ERR(desc))
|
||||
return PTR_ERR(desc);
|
||||
|
|
@ -1177,7 +1266,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
|
|||
}
|
||||
|
||||
info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
|
||||
info.op_tmpl = *spinand->op_templates.update_cache;
|
||||
info.op_tmpl = *spinand->op_templates->update_cache;
|
||||
info.op_tmpl.data.ecc = true;
|
||||
desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev,
|
||||
spinand->spimem, &info);
|
||||
|
|
@ -1186,7 +1275,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand,
|
|||
|
||||
spinand->dirmaps[plane].wdesc_ecc = desc;
|
||||
|
||||
info.op_tmpl = *spinand->op_templates.read_cache;
|
||||
info.op_tmpl = *spinand->op_templates->read_cache;
|
||||
info.op_tmpl.data.ecc = true;
|
||||
desc = spinand_create_rdesc(spinand, &info);
|
||||
if (IS_ERR(desc))
|
||||
|
|
@ -1227,6 +1316,7 @@ static const struct nand_ops spinand_ops = {
|
|||
static const struct spinand_manufacturer *spinand_manufacturers[] = {
|
||||
&alliancememory_spinand_manufacturer,
|
||||
&ato_spinand_manufacturer,
|
||||
&dosilicon_spinand_manufacturer,
|
||||
&esmt_8c_spinand_manufacturer,
|
||||
&esmt_c8_spinand_manufacturer,
|
||||
&fmsh_spinand_manufacturer,
|
||||
|
|
@ -1307,12 +1397,6 @@ static int spinand_manufacturer_init(struct spinand_device *spinand)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (spinand->configure_chip) {
|
||||
ret = spinand->configure_chip(spinand);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1323,8 +1407,101 @@ static void spinand_manufacturer_cleanup(struct spinand_device *spinand)
|
|||
return spinand->manufacturer->ops->cleanup(spinand);
|
||||
}
|
||||
|
||||
static bool spinand_op_is_odtr(const struct spi_mem_op *op)
|
||||
{
|
||||
return op->cmd.dtr && op->cmd.buswidth == 8;
|
||||
}
|
||||
|
||||
static void spinand_init_ssdr_templates(struct spinand_device *spinand)
|
||||
{
|
||||
struct spinand_mem_ops *tmpl = &spinand->ssdr_op_templates;
|
||||
|
||||
tmpl->reset = (struct spi_mem_op)SPINAND_RESET_1S_0_0_OP;
|
||||
tmpl->readid = (struct spi_mem_op)SPINAND_READID_1S_1S_1S_OP(0, 0, NULL, 0);
|
||||
tmpl->wr_en = (struct spi_mem_op)SPINAND_WR_EN_1S_0_0_OP;
|
||||
tmpl->wr_dis = (struct spi_mem_op)SPINAND_WR_DIS_1S_0_0_OP;
|
||||
tmpl->set_feature = (struct spi_mem_op)SPINAND_SET_FEATURE_1S_1S_1S_OP(0, NULL);
|
||||
tmpl->get_feature = (struct spi_mem_op)SPINAND_GET_FEATURE_1S_1S_1S_OP(0, NULL);
|
||||
tmpl->blk_erase = (struct spi_mem_op)SPINAND_BLK_ERASE_1S_1S_0_OP(0);
|
||||
tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_1S_1S_0_OP(0);
|
||||
tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_1S_1S_0_OP(0);
|
||||
spinand->op_templates = &spinand->ssdr_op_templates;
|
||||
spinand->bus_iface = SSDR;
|
||||
}
|
||||
|
||||
static int spinand_support_vendor_ops(struct spinand_device *spinand,
|
||||
const struct spinand_info *info,
|
||||
enum spinand_bus_interface iface)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!info->vendor_ops)
|
||||
return 0;
|
||||
/*
|
||||
* The vendor ops array is only used in order to verify this chip and all its memory
|
||||
* operations are supported. If we see patterns emerging, we could ideally name these
|
||||
* operations and define them at the SPI NAND core level instead.
|
||||
* For now, this only serves as a sanity check.
|
||||
*/
|
||||
for (i = 0; i < info->vendor_ops->nops; i++) {
|
||||
const struct spi_mem_op *op = &info->vendor_ops->ops[i];
|
||||
|
||||
if ((iface == SSDR && spinand_op_is_odtr(op)) ||
|
||||
(iface == ODTR && !spinand_op_is_odtr(op)))
|
||||
continue;
|
||||
|
||||
if (!spi_mem_supports_op(spinand->spimem, op))
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spinand_init_odtr_instruction_set(struct spinand_device *spinand)
|
||||
{
|
||||
struct spinand_mem_ops *tmpl = &spinand->odtr_op_templates;
|
||||
|
||||
tmpl->reset = (struct spi_mem_op)SPINAND_RESET_8D_0_0_OP;
|
||||
if (!spi_mem_supports_op(spinand->spimem, &tmpl->reset))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
tmpl->readid = (struct spi_mem_op)SPINAND_READID_8D_8D_8D_OP(0, 0, NULL, 0);
|
||||
if (!spi_mem_supports_op(spinand->spimem, &tmpl->readid))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
tmpl->wr_en = (struct spi_mem_op)SPINAND_WR_EN_8D_0_0_OP;
|
||||
if (!spi_mem_supports_op(spinand->spimem, &tmpl->wr_en))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
tmpl->wr_dis = (struct spi_mem_op)SPINAND_WR_DIS_8D_0_0_OP;
|
||||
if (!spi_mem_supports_op(spinand->spimem, &tmpl->wr_dis))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
tmpl->set_feature = (struct spi_mem_op)SPINAND_SET_FEATURE_8D_8D_8D_OP(0, NULL);
|
||||
if (!spi_mem_supports_op(spinand->spimem, &tmpl->set_feature))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
tmpl->get_feature = (struct spi_mem_op)SPINAND_GET_FEATURE_8D_8D_8D_OP(0, NULL);
|
||||
if (!spi_mem_supports_op(spinand->spimem, &tmpl->get_feature))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
tmpl->blk_erase = (struct spi_mem_op)SPINAND_BLK_ERASE_8D_8D_0_OP(0);
|
||||
if (!spi_mem_supports_op(spinand->spimem, &tmpl->blk_erase))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0);
|
||||
if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_8D_8D_0_OP(0);
|
||||
if (!spi_mem_supports_op(spinand->spimem, &tmpl->prog_exec))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_mem_op *
|
||||
spinand_select_op_variant(struct spinand_device *spinand,
|
||||
spinand_select_op_variant(struct spinand_device *spinand, enum spinand_bus_interface iface,
|
||||
const struct spinand_op_variants *variants)
|
||||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
|
|
@ -1338,6 +1515,10 @@ spinand_select_op_variant(struct spinand_device *spinand,
|
|||
unsigned int nbytes;
|
||||
int ret;
|
||||
|
||||
if ((iface == SSDR && spinand_op_is_odtr(&op)) ||
|
||||
(iface == ODTR && !spinand_op_is_odtr(&op)))
|
||||
continue;
|
||||
|
||||
nbytes = nanddev_per_page_oobsize(nand) +
|
||||
nanddev_page_size(nand);
|
||||
|
||||
|
|
@ -1389,6 +1570,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
|
|||
u8 *id = spinand->id.data;
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < table_size; i++) {
|
||||
const struct spinand_info *info = &table[i];
|
||||
|
|
@ -1413,28 +1595,59 @@ int spinand_match_and_init(struct spinand_device *spinand,
|
|||
spinand->read_retries = table[i].read_retries;
|
||||
spinand->set_read_retry = table[i].set_read_retry;
|
||||
|
||||
op = spinand_select_op_variant(spinand,
|
||||
/* I/O variants selection with single-spi SDR commands */
|
||||
|
||||
op = spinand_select_op_variant(spinand, SSDR,
|
||||
info->op_variants.read_cache);
|
||||
if (!op)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spinand->op_templates.read_cache = op;
|
||||
spinand->ssdr_op_templates.read_cache = op;
|
||||
|
||||
op = spinand_select_op_variant(spinand,
|
||||
op = spinand_select_op_variant(spinand, SSDR,
|
||||
info->op_variants.write_cache);
|
||||
if (!op)
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spinand->op_templates.write_cache = op;
|
||||
spinand->ssdr_op_templates.write_cache = op;
|
||||
|
||||
op = spinand_select_op_variant(spinand,
|
||||
op = spinand_select_op_variant(spinand, SSDR,
|
||||
info->op_variants.update_cache);
|
||||
spinand->op_templates.update_cache = op;
|
||||
if (!op)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spinand->ssdr_op_templates.update_cache = op;
|
||||
|
||||
ret = spinand_support_vendor_ops(spinand, info, SSDR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* I/O variants selection with octo-spi DDR commands (optional) */
|
||||
|
||||
ret = spinand_init_odtr_instruction_set(spinand);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
ret = spinand_support_vendor_ops(spinand, info, ODTR);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
op = spinand_select_op_variant(spinand, ODTR,
|
||||
info->op_variants.read_cache);
|
||||
spinand->odtr_op_templates.read_cache = op;
|
||||
|
||||
op = spinand_select_op_variant(spinand, ODTR,
|
||||
info->op_variants.write_cache);
|
||||
spinand->odtr_op_templates.write_cache = op;
|
||||
|
||||
op = spinand_select_op_variant(spinand, ODTR,
|
||||
info->op_variants.update_cache);
|
||||
spinand->odtr_op_templates.update_cache = op;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int spinand_detect(struct spinand_device *spinand)
|
||||
|
|
@ -1470,6 +1683,56 @@ static int spinand_detect(struct spinand_device *spinand)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int spinand_configure_chip(struct spinand_device *spinand)
|
||||
{
|
||||
bool odtr = false, quad_enable = false;
|
||||
int ret;
|
||||
|
||||
if (spinand->odtr_op_templates.read_cache &&
|
||||
spinand->odtr_op_templates.write_cache &&
|
||||
spinand->odtr_op_templates.update_cache)
|
||||
odtr = true;
|
||||
|
||||
if (odtr) {
|
||||
if (!spinand->configure_chip)
|
||||
goto try_ssdr;
|
||||
|
||||
/* ODTR bus interface configuration happens here */
|
||||
ret = spinand->configure_chip(spinand, ODTR);
|
||||
if (ret) {
|
||||
spinand->odtr_op_templates.read_cache = NULL;
|
||||
spinand->odtr_op_templates.write_cache = NULL;
|
||||
spinand->odtr_op_templates.update_cache = NULL;
|
||||
goto try_ssdr;
|
||||
}
|
||||
|
||||
spinand->op_templates = &spinand->odtr_op_templates;
|
||||
spinand->bus_iface = ODTR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try_ssdr:
|
||||
if (spinand->flags & SPINAND_HAS_QE_BIT) {
|
||||
if (spinand->ssdr_op_templates.read_cache->data.buswidth == 4 ||
|
||||
spinand->ssdr_op_templates.write_cache->data.buswidth == 4 ||
|
||||
spinand->ssdr_op_templates.update_cache->data.buswidth == 4)
|
||||
quad_enable = true;
|
||||
}
|
||||
|
||||
ret = spinand_init_quad_enable(spinand, quad_enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (spinand->configure_chip) {
|
||||
ret = spinand->configure_chip(spinand, SSDR);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spinand_init_flash(struct spinand_device *spinand)
|
||||
{
|
||||
struct device *dev = &spinand->spimem->spi->dev;
|
||||
|
|
@ -1480,10 +1743,6 @@ static int spinand_init_flash(struct spinand_device *spinand)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = spinand_init_quad_enable(spinand);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -1496,19 +1755,25 @@ static int spinand_init_flash(struct spinand_device *spinand)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = spinand_configure_chip(spinand);
|
||||
if (ret)
|
||||
goto manuf_cleanup;
|
||||
|
||||
/* After power up, all blocks are locked, so unlock them here. */
|
||||
for (i = 0; i < nand->memorg.ntargets; i++) {
|
||||
ret = spinand_select_target(spinand, i);
|
||||
if (ret)
|
||||
break;
|
||||
goto manuf_cleanup;
|
||||
|
||||
ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED);
|
||||
if (ret)
|
||||
break;
|
||||
goto manuf_cleanup;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
spinand_manufacturer_cleanup(spinand);
|
||||
return 0;
|
||||
|
||||
manuf_cleanup:
|
||||
spinand_manufacturer_cleanup(spinand);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1529,6 +1794,32 @@ static void spinand_mtd_resume(struct mtd_info *mtd)
|
|||
spinand_ecc_enable(spinand, false);
|
||||
}
|
||||
|
||||
static int spinand_mtd_suspend(struct mtd_info *mtd)
|
||||
{
|
||||
struct spinand_device *spinand = mtd_to_spinand(mtd);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Return to SSDR interface in the suspend path to make sure the
|
||||
* reset operation is correctly processed upon resume.
|
||||
*
|
||||
* Note: Once back in SSDR mode, every operation but the page helpers
|
||||
* (dirmap based I/O accessors) will work. Page accesses would require
|
||||
* destroying and recreating the dirmaps twice to work, which would be
|
||||
* impacting for no reason, as this is just a transitional state.
|
||||
*/
|
||||
if (spinand->bus_iface == ODTR) {
|
||||
ret = spinand->configure_chip(spinand, SSDR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spinand->op_templates = &spinand->ssdr_op_templates;
|
||||
spinand->bus_iface = SSDR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spinand_init(struct spinand_device *spinand)
|
||||
{
|
||||
struct device *dev = &spinand->spimem->spi->dev;
|
||||
|
|
@ -1544,6 +1835,8 @@ static int spinand_init(struct spinand_device *spinand)
|
|||
if (!spinand->scratchbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
spinand_init_ssdr_templates(spinand);
|
||||
|
||||
ret = spinand_detect(spinand);
|
||||
if (ret)
|
||||
goto err_free_bufs;
|
||||
|
|
@ -1596,6 +1889,7 @@ static int spinand_init(struct spinand_device *spinand)
|
|||
mtd->_block_isreserved = spinand_mtd_block_isreserved;
|
||||
mtd->_erase = spinand_mtd_erase;
|
||||
mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
|
||||
mtd->_suspend = spinand_mtd_suspend;
|
||||
mtd->_resume = spinand_mtd_resume;
|
||||
|
||||
if (spinand_user_otp_size(spinand) || spinand_fact_otp_size(spinand)) {
|
||||
|
|
|
|||
91
drivers/mtd/nand/spi/dosilicon.c
Normal file
91
drivers/mtd/nand/spi/dosilicon.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Author: Ahmed Naseef <naseefkm@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mtd/spinand.h>
|
||||
|
||||
#define SPINAND_MFR_DOSILICON 0xE5
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
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),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(update_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
static int ds35xx_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
if (section > 3)
|
||||
return -ERANGE;
|
||||
|
||||
region->offset = 8 + (section * 16);
|
||||
region->length = 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ds35xx_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
if (section > 3)
|
||||
return -ERANGE;
|
||||
|
||||
if (section == 0) {
|
||||
/* reserve 2 bytes for the BBM */
|
||||
region->offset = 2;
|
||||
region->length = 6;
|
||||
} else {
|
||||
region->offset = section * 16;
|
||||
region->length = 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mtd_ooblayout_ops ds35xx_ooblayout = {
|
||||
.ecc = ds35xx_ooblayout_ecc,
|
||||
.free = ds35xx_ooblayout_free,
|
||||
};
|
||||
|
||||
static const struct spinand_info dosilicon_spinand_table[] = {
|
||||
SPINAND_INFO("DS35Q1GA",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(4, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&ds35xx_ooblayout, NULL)),
|
||||
SPINAND_INFO("DS35M1GA",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x21),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(4, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&ds35xx_ooblayout, NULL)),
|
||||
};
|
||||
|
||||
static const struct spinand_manufacturer_ops dosilicon_spinand_manuf_ops = {
|
||||
};
|
||||
|
||||
const struct spinand_manufacturer dosilicon_spinand_manufacturer = {
|
||||
.id = SPINAND_MFR_DOSILICON,
|
||||
.name = "Dosilicon",
|
||||
.chips = dosilicon_spinand_table,
|
||||
.nchips = ARRAY_SIZE(dosilicon_spinand_table),
|
||||
.ops = &dosilicon_spinand_manuf_ops,
|
||||
};
|
||||
|
|
@ -138,8 +138,8 @@ static int f50l1g41lb_user_otp_info(struct spinand_device *spinand, size_t len,
|
|||
static int f50l1g41lb_otp_lock(struct spinand_device *spinand, loff_t from,
|
||||
size_t len)
|
||||
{
|
||||
struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
|
||||
struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0);
|
||||
struct spi_mem_op write_op = SPINAND_OP(spinand, wr_en);
|
||||
struct spi_mem_op exec_op = SPINAND_OP(spinand, prog_exec, 0);
|
||||
u8 status;
|
||||
int ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@
|
|||
|
||||
#define SPINAND_MFR_FORESEE 0xCD
|
||||
|
||||
#define F35SQB002G_STATUS_ECC_MASK (7 << 4)
|
||||
#define F35SQB002G_STATUS_ECC_NO_BITFLIPS (0 << 4)
|
||||
#define F35SQB002G_STATUS_ECC_1_3_BITFLIPS (1 << 4)
|
||||
#define F35SQB002G_STATUS_ECC_UNCOR_ERROR (7 << 4)
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
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),
|
||||
|
|
@ -70,6 +75,25 @@ static int f35sqa002g_ecc_get_status(struct spinand_device *spinand, u8 status)
|
|||
return -EBADMSG;
|
||||
}
|
||||
|
||||
static int f35sqb002g_ecc_get_status(struct spinand_device *spinand, u8 status)
|
||||
{
|
||||
switch (status & F35SQB002G_STATUS_ECC_MASK) {
|
||||
case F35SQB002G_STATUS_ECC_NO_BITFLIPS:
|
||||
return 0;
|
||||
|
||||
case F35SQB002G_STATUS_ECC_1_3_BITFLIPS:
|
||||
return 3;
|
||||
|
||||
case F35SQB002G_STATUS_ECC_UNCOR_ERROR:
|
||||
return -EBADMSG;
|
||||
|
||||
default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
|
||||
return ((status & F35SQB002G_STATUS_ECC_MASK) >> 4) + 2;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct spinand_info foresee_spinand_table[] = {
|
||||
SPINAND_INFO("F35SQA002G",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x72, 0x72),
|
||||
|
|
@ -91,6 +115,16 @@ static const struct spinand_info foresee_spinand_table[] = {
|
|||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&f35sqa002g_ooblayout,
|
||||
f35sqa002g_ecc_get_status)),
|
||||
SPINAND_INFO("F35SQB002G",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x52, 0x52),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&f35sqa002g_ooblayout,
|
||||
f35sqb002g_ecc_get_status)),
|
||||
};
|
||||
|
||||
static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = {
|
||||
|
|
|
|||
|
|
@ -266,8 +266,8 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
|
|||
u8 status)
|
||||
{
|
||||
u8 status2;
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(GD5FXGQXXEXXG_REG_STATUS2,
|
||||
spinand->scratchbuf);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, get_feature,
|
||||
GD5FXGQXXEXXG_REG_STATUS2, spinand->scratchbuf);
|
||||
int ret;
|
||||
|
||||
switch (status & STATUS_ECC_MASK) {
|
||||
|
|
@ -309,8 +309,8 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
|
|||
u8 status)
|
||||
{
|
||||
u8 status2;
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(GD5FXGQXXEXXG_REG_STATUS2,
|
||||
spinand->scratchbuf);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, get_feature,
|
||||
GD5FXGQXXEXXG_REG_STATUS2, spinand->scratchbuf);
|
||||
int ret;
|
||||
|
||||
switch (status & STATUS_ECC_MASK) {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,23 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
|
|||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
#define SPINAND_MACRONIX_READ_ECCSR_1S_0_1S(buf) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_DUMMY(1, 1), \
|
||||
SPI_MEM_OP_DATA_IN(1, buf, 1))
|
||||
|
||||
static SPINAND_OP_VARIANTS(macronix_ops,
|
||||
SPINAND_MACRONIX_READ_ECCSR_1S_0_1S(NULL));
|
||||
|
||||
static struct spi_mem_op
|
||||
spinand_fill_macronix_read_eccsr_op(struct spinand_device *spinand, void *valptr)
|
||||
{
|
||||
WARN_ON_ONCE(spinand->bus_iface != SSDR);
|
||||
|
||||
return (struct spi_mem_op)SPINAND_MACRONIX_READ_ECCSR_1S_0_1S(valptr);
|
||||
}
|
||||
|
||||
static int mx35lfxge4ab_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
|
|
@ -67,12 +84,10 @@ static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
|
|||
static int macronix_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
|
||||
{
|
||||
struct macronix_priv *priv = spinand->priv;
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1),
|
||||
SPI_MEM_OP_NO_ADDR,
|
||||
SPI_MEM_OP_DUMMY(1, 1),
|
||||
SPI_MEM_OP_DATA_IN(1, eccsr, 1));
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, macronix_read_eccsr, eccsr);
|
||||
int ret;
|
||||
|
||||
int ret = spi_mem_exec_op(spinand->spimem, &op);
|
||||
ret = spi_mem_exec_op(spinand->spimem, &op);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -148,8 +163,8 @@ static int macronix_set_cont_read(struct spinand_device *spinand, bool enable)
|
|||
static int macronix_set_read_retry(struct spinand_device *spinand,
|
||||
unsigned int retry_mode)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(MACRONIX_FEATURE_ADDR_READ_RETRY,
|
||||
spinand->scratchbuf);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, set_feature,
|
||||
MACRONIX_FEATURE_ADDR_READ_RETRY, spinand->scratchbuf);
|
||||
|
||||
*spinand->scratchbuf = retry_mode;
|
||||
return spi_mem_exec_op(spinand->spimem, &op);
|
||||
|
|
@ -164,6 +179,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status)),
|
||||
SPINAND_INFO("MX35LF2GE4AB",
|
||||
|
|
@ -185,6 +201,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read),
|
||||
|
|
@ -198,6 +215,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read),
|
||||
|
|
@ -268,6 +286,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status)),
|
||||
SPINAND_INFO("MX31UF1GE4BC",
|
||||
|
|
@ -278,6 +297,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status)),
|
||||
|
||||
|
|
@ -291,6 +311,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
SPINAND_HAS_QE_BIT |
|
||||
SPINAND_HAS_PROG_PLANE_SELECT_BIT |
|
||||
SPINAND_HAS_READ_PLANE_SELECT_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status)),
|
||||
SPINAND_INFO("MX35UF4G24AD",
|
||||
|
|
@ -302,6 +323,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT |
|
||||
SPINAND_HAS_PROG_PLANE_SELECT_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
|
|
@ -314,6 +336,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
|
|
@ -326,6 +349,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read),
|
||||
|
|
@ -341,6 +365,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
SPINAND_HAS_QE_BIT |
|
||||
SPINAND_HAS_PROG_PLANE_SELECT_BIT |
|
||||
SPINAND_HAS_READ_PLANE_SELECT_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status)),
|
||||
SPINAND_INFO("MX35UF2G24AD",
|
||||
|
|
@ -352,6 +377,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT |
|
||||
SPINAND_HAS_PROG_PLANE_SELECT_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
|
|
@ -364,6 +390,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
|
|
@ -376,6 +403,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read),
|
||||
|
|
@ -389,6 +417,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read)),
|
||||
|
|
@ -400,6 +429,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status)),
|
||||
SPINAND_INFO("MX35UF1G24AD",
|
||||
|
|
@ -410,6 +440,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
|
|
@ -422,6 +453,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read),
|
||||
|
|
@ -435,6 +467,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read)),
|
||||
|
|
@ -446,6 +479,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status)),
|
||||
SPINAND_INFO("MX3UF2GE4BC",
|
||||
|
|
@ -456,6 +490,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_INFO_VENDOR_OPS(¯onix_ops),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status)),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -137,8 +137,8 @@ static const struct mtd_ooblayout_ops micron_4_ooblayout = {
|
|||
static int micron_select_target(struct spinand_device *spinand,
|
||||
unsigned int target)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(MICRON_DIE_SELECT_REG,
|
||||
spinand->scratchbuf);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, set_feature,
|
||||
MICRON_DIE_SELECT_REG, spinand->scratchbuf);
|
||||
|
||||
if (target > 1)
|
||||
return -EINVAL;
|
||||
|
|
@ -251,8 +251,8 @@ static int mt29f2g01abagd_user_otp_info(struct spinand_device *spinand,
|
|||
static int mt29f2g01abagd_otp_lock(struct spinand_device *spinand, loff_t from,
|
||||
size_t len)
|
||||
{
|
||||
struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
|
||||
struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0);
|
||||
struct spi_mem_op write_op = SPINAND_OP(spinand, wr_en);
|
||||
struct spi_mem_op exec_op = SPINAND_OP(spinand, prog_exec, 0);
|
||||
u8 status;
|
||||
int ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,8 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
|
|||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
u8 mbf = 0;
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(0x30, spinand->scratchbuf);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, get_feature,
|
||||
0x30, spinand->scratchbuf);
|
||||
|
||||
switch (status & STATUS_ECC_MASK) {
|
||||
case STATUS_ECC_NO_BITFLIPS:
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#define W25N0XJW_SR4 0xD0
|
||||
#define W25N0XJW_SR4_HS BIT(2)
|
||||
|
||||
#define W35N01JW_VCR_IO_MODE 0x00
|
||||
#define W35N01JW_VCR_IO_MODE_REG 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
|
||||
|
|
@ -36,6 +36,8 @@
|
|||
*/
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_octal_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(0, 24, NULL, 0, 120 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(0, 16, NULL, 0, 86 * HZ_PER_MHZ),
|
||||
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),
|
||||
|
|
@ -48,11 +50,13 @@ static SPINAND_OP_VARIANTS(read_cache_octal_variants,
|
|||
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_8D_8D_8D_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_8S_8S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_8S_OP(0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(update_cache_octal_variants,
|
||||
SPINAND_PROG_LOAD_8D_8D_8D_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_8S_8S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
|
|
@ -87,6 +91,47 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
|
|||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
#define SPINAND_WINBOND_WRITE_VCR_1S_1S_1S(reg, buf) \
|
||||
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, buf, 1))
|
||||
|
||||
#define SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(reg, buf) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x81, 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(4, reg, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_DTR_OP_DATA_OUT(2, buf, 8))
|
||||
|
||||
static SPINAND_OP_VARIANTS(winbond_w35_ops,
|
||||
SPINAND_WINBOND_WRITE_VCR_1S_1S_1S(0, NULL),
|
||||
SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(0, NULL));
|
||||
|
||||
static struct spi_mem_op
|
||||
spinand_fill_winbond_write_vcr_op(struct spinand_device *spinand, u8 reg, void *valptr)
|
||||
{
|
||||
return (spinand->bus_iface == SSDR) ?
|
||||
(struct spi_mem_op)SPINAND_WINBOND_WRITE_VCR_1S_1S_1S(reg, valptr) :
|
||||
(struct spi_mem_op)SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(reg, valptr);
|
||||
}
|
||||
|
||||
#define SPINAND_WINBOND_SELECT_TARGET_1S_0_1S(buf) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xc2, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(1, buf, 1))
|
||||
|
||||
static SPINAND_OP_VARIANTS(winbond_w25_ops,
|
||||
SPINAND_WINBOND_SELECT_TARGET_1S_0_1S(NULL));
|
||||
|
||||
static struct spi_mem_op
|
||||
spinand_fill_winbond_select_target_op(struct spinand_device *spinand, void *valptr)
|
||||
{
|
||||
WARN_ON_ONCE(spinand->bus_iface != SSDR);
|
||||
|
||||
return (struct spi_mem_op)SPINAND_WINBOND_SELECT_TARGET_1S_0_1S(valptr);
|
||||
}
|
||||
|
||||
static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
|
|
@ -119,12 +164,8 @@ static const struct mtd_ooblayout_ops w25m02gv_ooblayout = {
|
|||
static int w25m02gv_select_target(struct spinand_device *spinand,
|
||||
unsigned int target)
|
||||
{
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0xc2, 1),
|
||||
SPI_MEM_OP_NO_ADDR,
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_OUT(1,
|
||||
spinand->scratchbuf,
|
||||
1));
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, winbond_select_target,
|
||||
spinand->scratchbuf);
|
||||
|
||||
*spinand->scratchbuf = target;
|
||||
return spi_mem_exec_op(spinand->spimem, &op);
|
||||
|
|
@ -251,7 +292,8 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
|
|||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
u8 mbf = 0;
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(0x30, spinand->scratchbuf);
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, get_feature,
|
||||
0x30, spinand->scratchbuf);
|
||||
|
||||
switch (status & STATUS_ECC_MASK) {
|
||||
case STATUS_ECC_NO_BITFLIPS:
|
||||
|
|
@ -284,14 +326,18 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int w25n0xjw_hs_cfg(struct spinand_device *spinand)
|
||||
static int w25n0xjw_hs_cfg(struct spinand_device *spinand,
|
||||
enum spinand_bus_interface iface)
|
||||
{
|
||||
const struct spi_mem_op *op;
|
||||
bool hs;
|
||||
u8 sr4;
|
||||
int ret;
|
||||
|
||||
op = spinand->op_templates.read_cache;
|
||||
if (iface != SSDR)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
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 &&
|
||||
|
|
@ -320,11 +366,8 @@ static int w25n0xjw_hs_cfg(struct spinand_device *spinand)
|
|||
|
||||
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));
|
||||
struct spi_mem_op op = SPINAND_OP(spinand, winbond_write_vcr,
|
||||
reg, spinand->scratchbuf);
|
||||
int ret;
|
||||
|
||||
*spinand->scratchbuf = val;
|
||||
|
|
@ -347,32 +390,28 @@ static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
|
||||
static int w35n0xjw_vcr_cfg(struct spinand_device *spinand,
|
||||
enum spinand_bus_interface iface)
|
||||
{
|
||||
const struct spi_mem_op *op;
|
||||
const struct spi_mem_op *ref_op;
|
||||
unsigned int dummy_cycles;
|
||||
bool dtr, single;
|
||||
u8 io_mode;
|
||||
int ret;
|
||||
|
||||
op = spinand->op_templates.read_cache;
|
||||
switch (iface) {
|
||||
case SSDR:
|
||||
ref_op = spinand->ssdr_op_templates.read_cache;
|
||||
break;
|
||||
case ODTR:
|
||||
ref_op = spinand->odtr_op_templates.read_cache;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
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);
|
||||
dummy_cycles = ((ref_op->dummy.nbytes * 8) / ref_op->dummy.buswidth) /
|
||||
(ref_op->dummy.dtr ? 2 : 1);
|
||||
switch (dummy_cycles) {
|
||||
case 8:
|
||||
case 12:
|
||||
|
|
@ -384,10 +423,28 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
|
|||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_DUMMY_CLOCK_REG, dummy_cycles);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
single = (ref_op->cmd.buswidth == 1 &&
|
||||
ref_op->addr.buswidth == 1 &&
|
||||
ref_op->data.buswidth == 1);
|
||||
dtr = (ref_op->cmd.dtr && ref_op->addr.dtr && ref_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_REG, io_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -448,6 +505,7 @@ static const struct spinand_info winbond_spinand_table[] = {
|
|||
&write_cache_octal_variants,
|
||||
&update_cache_octal_variants),
|
||||
0,
|
||||
SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops),
|
||||
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
|
||||
SPINAND_INFO("W35N02JW", /* 1.8V */
|
||||
|
|
@ -458,6 +516,7 @@ static const struct spinand_info winbond_spinand_table[] = {
|
|||
&write_cache_octal_variants,
|
||||
&update_cache_octal_variants),
|
||||
0,
|
||||
SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops),
|
||||
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
|
||||
SPINAND_INFO("W35N04JW", /* 1.8V */
|
||||
|
|
@ -468,6 +527,7 @@ static const struct spinand_info winbond_spinand_table[] = {
|
|||
&write_cache_octal_variants,
|
||||
&update_cache_octal_variants),
|
||||
0,
|
||||
SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops),
|
||||
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
|
||||
/* 2G-bit densities */
|
||||
|
|
@ -479,6 +539,7 @@ static const struct spinand_info winbond_spinand_table[] = {
|
|||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_INFO_VENDOR_OPS(&winbond_w25_ops),
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
|
||||
SPINAND_SELECT_TARGET(w25m02gv_select_target)),
|
||||
SPINAND_INFO("W25N02JW", /* high-speed 1.8V */
|
||||
|
|
|
|||
|
|
@ -4,12 +4,6 @@
|
|||
|
||||
#ifdef CONFIG_MTD_OF_PARTS_BCM4908
|
||||
int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
|
||||
#else
|
||||
static inline int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts,
|
||||
int nr_parts)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -23,13 +23,17 @@ struct fixed_partitions_quirks {
|
|||
int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MTD_OF_PARTS_BCM4908
|
||||
static struct fixed_partitions_quirks bcm4908_partitions_quirks = {
|
||||
.post_parse = bcm4908_partitions_post_parse,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_OF_PARTS_LINKSYS_NS
|
||||
static struct fixed_partitions_quirks linksys_ns_partitions_quirks = {
|
||||
.post_parse = linksys_ns_partitions_post_parse,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct of_device_id parse_ofpart_match_table[];
|
||||
|
||||
|
|
@ -77,6 +81,7 @@ static int parse_fixed_partitions(struct mtd_info *master,
|
|||
of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
|
||||
if (dedicated && !of_id) {
|
||||
/* The 'partitions' subnode might be used by another parser */
|
||||
of_node_put(ofpart_node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -91,12 +96,18 @@ static int parse_fixed_partitions(struct mtd_info *master,
|
|||
nr_parts++;
|
||||
}
|
||||
|
||||
if (nr_parts == 0)
|
||||
if (nr_parts == 0) {
|
||||
if (dedicated)
|
||||
of_node_put(ofpart_node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
|
||||
if (!parts)
|
||||
if (!parts) {
|
||||
if (dedicated)
|
||||
of_node_put(ofpart_node);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for_each_child_of_node(ofpart_node, pp) {
|
||||
|
|
@ -175,6 +186,9 @@ static int parse_fixed_partitions(struct mtd_info *master,
|
|||
if (quirks && quirks->post_parse)
|
||||
quirks->post_parse(master, parts, nr_parts);
|
||||
|
||||
if (dedicated)
|
||||
of_node_put(ofpart_node);
|
||||
|
||||
*pparts = parts;
|
||||
return nr_parts;
|
||||
|
||||
|
|
@ -183,6 +197,8 @@ ofpart_fail:
|
|||
master->name, pp, mtd_node);
|
||||
ret = -EINVAL;
|
||||
ofpart_none:
|
||||
if (dedicated)
|
||||
of_node_put(ofpart_node);
|
||||
of_node_put(pp);
|
||||
kfree(parts);
|
||||
return ret;
|
||||
|
|
@ -192,8 +208,12 @@ static const struct of_device_id parse_ofpart_match_table[] = {
|
|||
/* Generic */
|
||||
{ .compatible = "fixed-partitions" },
|
||||
/* Customized */
|
||||
#ifdef CONFIG_MTD_OF_PARTS_BCM4908
|
||||
{ .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, },
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_OF_PARTS_LINKSYS_NS
|
||||
{ .compatible = "linksys,ns-partitions", .data = &linksys_ns_partitions_quirks, },
|
||||
#endif
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
|
||||
|
|
|
|||
|
|
@ -6,13 +6,6 @@
|
|||
int linksys_ns_partitions_post_parse(struct mtd_info *mtd,
|
||||
struct mtd_partition *parts,
|
||||
int nr_parts);
|
||||
#else
|
||||
static inline int linksys_ns_partitions_post_parse(struct mtd_info *mtd,
|
||||
struct mtd_partition *parts,
|
||||
int nr_parts)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd,
|
|||
return idx;
|
||||
|
||||
err_free:
|
||||
kfree(buf);
|
||||
for (idx -= 1; idx >= 0; idx--)
|
||||
kfree(parts[idx].name);
|
||||
err_free_parts:
|
||||
|
|
|
|||
|
|
@ -394,19 +394,15 @@ static void hisi_spi_nor_unregister_all(struct hifmc_host *host)
|
|||
static int hisi_spi_nor_register_all(struct hifmc_host *host)
|
||||
{
|
||||
struct device *dev = host->dev;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
for_each_available_child_of_node(dev->of_node, np) {
|
||||
for_each_available_child_of_node_scoped(dev->of_node, np) {
|
||||
ret = hisi_spi_nor_register(np, host);
|
||||
if (ret) {
|
||||
of_node_put(np);
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (host->num_chip == HIFMC_MAX_CHIP_NUM) {
|
||||
dev_warn(dev, "Flash device number exceeds the maximum chipselect number\n");
|
||||
of_node_put(np);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,14 @@
|
|||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_WR_EN_DIS_1S_0_0_OP(enable) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD((enable) ? 0x06 : 0x04, 1), \
|
||||
#define SPINAND_WR_EN_1S_0_0_OP \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x06, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_WR_DIS_1S_0_0_OP \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x04, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
|
@ -233,10 +239,75 @@
|
|||
SPI_MEM_OP_DATA_OUT(len, buf, 8))
|
||||
|
||||
/**
|
||||
* Standard SPI NAND flash commands
|
||||
* Octal DDR SPI NAND flash operations
|
||||
*/
|
||||
#define SPINAND_CMD_PROG_LOAD_X4 0x32
|
||||
#define SPINAND_CMD_PROG_LOAD_RDM_DATA_X4 0x34
|
||||
|
||||
#define SPINAND_RESET_8D_0_0_OP \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0xff, 8), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_READID_8D_8D_8D_OP(naddr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9f, 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(naddr, 0, 8), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 8), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 8))
|
||||
|
||||
#define SPINAND_WR_EN_8D_0_0_OP \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x06, 8), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_WR_DIS_8D_0_0_OP \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x04, 8), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_SET_FEATURE_8D_8D_8D_OP(reg, valptr) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x1f, 8), \
|
||||
SPI_MEM_DTR_OP_RPT_ADDR(reg, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_DTR_OP_DATA_OUT(2, valptr, 8))
|
||||
|
||||
#define SPINAND_GET_FEATURE_8D_8D_8D_OP(reg, valptr) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x0f, 8), \
|
||||
SPI_MEM_DTR_OP_RPT_ADDR(reg, 8), \
|
||||
SPI_MEM_DTR_OP_DUMMY(14, 8), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(2, valptr, 8))
|
||||
|
||||
#define SPINAND_BLK_ERASE_8D_8D_0_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0xd8, 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PAGE_READ_8D_8D_0_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x13, 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 8), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PROG_EXEC_8D_8D_0_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x10, 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PROG_LOAD_8D_8D_8D_OP(reset, addr, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD((reset ? 0xc2 : 0xc4), 8), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_DTR_OP_DATA_OUT(len, buf, 8))
|
||||
|
||||
/* feature register */
|
||||
#define REG_BLOCK_LOCK 0xa0
|
||||
|
|
@ -261,7 +332,7 @@
|
|||
struct spinand_op;
|
||||
struct spinand_device;
|
||||
|
||||
#define SPINAND_MAX_ID_LEN 5
|
||||
#define SPINAND_MAX_ID_LEN 6
|
||||
/*
|
||||
* For erase, write and read operation, we got the following timings :
|
||||
* tBERS (erase) 1ms to 4ms
|
||||
|
|
@ -287,7 +358,7 @@ struct spinand_device;
|
|||
|
||||
/**
|
||||
* struct spinand_id - SPI NAND id structure
|
||||
* @data: buffer containing the id bytes. Currently 4 bytes large, but can
|
||||
* @data: buffer containing the id bytes. Currently 6 bytes large, but can
|
||||
* be extended if required
|
||||
* @len: ID length
|
||||
*/
|
||||
|
|
@ -354,6 +425,7 @@ struct spinand_manufacturer {
|
|||
/* SPI NAND manufacturers */
|
||||
extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer ato_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer dosilicon_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer esmt_8c_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer fmsh_spinand_manufacturer;
|
||||
|
|
@ -481,6 +553,16 @@ struct spinand_user_otp {
|
|||
const struct spinand_user_otp_ops *ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum spinand_bus_interface - SPI NAND bus interface types
|
||||
* @SSDR: Bus configuration supporting all 1S-XX-XX operations, including dual and quad
|
||||
* @ODTR: Bus configuration supporting only 8D-8D-8D operations
|
||||
*/
|
||||
enum spinand_bus_interface {
|
||||
SSDR,
|
||||
ODTR,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spinand_info - Structure used to describe SPI NAND chips
|
||||
* @model: model name
|
||||
|
|
@ -493,6 +575,7 @@ struct spinand_user_otp {
|
|||
* @op_variants.read_cache: variants of the read-cache operation
|
||||
* @op_variants.write_cache: variants of the write-cache operation
|
||||
* @op_variants.update_cache: variants of the update-cache operation
|
||||
* @vendor_ops: vendor specific operations
|
||||
* @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
|
||||
|
|
@ -517,9 +600,11 @@ struct spinand_info {
|
|||
const struct spinand_op_variants *write_cache;
|
||||
const struct spinand_op_variants *update_cache;
|
||||
} op_variants;
|
||||
const struct spinand_op_variants *vendor_ops;
|
||||
int (*select_target)(struct spinand_device *spinand,
|
||||
unsigned int target);
|
||||
int (*configure_chip)(struct spinand_device *spinand);
|
||||
int (*configure_chip)(struct spinand_device *spinand,
|
||||
enum spinand_bus_interface iface);
|
||||
int (*set_cont_read)(struct spinand_device *spinand,
|
||||
bool enable);
|
||||
struct spinand_fact_otp fact_otp;
|
||||
|
|
@ -543,6 +628,9 @@ struct spinand_info {
|
|||
.update_cache = __update, \
|
||||
}
|
||||
|
||||
#define SPINAND_INFO_VENDOR_OPS(__ops) \
|
||||
.vendor_ops = __ops
|
||||
|
||||
#define SPINAND_ECCINFO(__ooblayout, __get_status) \
|
||||
.eccinfo = { \
|
||||
.ooblayout = __ooblayout, \
|
||||
|
|
@ -599,6 +687,36 @@ struct spinand_dirmap {
|
|||
struct spi_mem_dirmap_desc *rdesc_ecc;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spinand_mem_ops - SPI NAND memory operations
|
||||
* @reset: reset op template
|
||||
* @readid: read ID op template
|
||||
* @wr_en: write enable op template
|
||||
* @wr_dis: write disable op template
|
||||
* @set_feature: set feature op template
|
||||
* @get_feature: get feature op template
|
||||
* @blk_erase: blk erase op template
|
||||
* @page_read: page read op template
|
||||
* @prog_exec: prog exec op template
|
||||
* @read_cache: read cache op template
|
||||
* @write_cache: write cache op template
|
||||
* @update_cache: update cache op template
|
||||
*/
|
||||
struct spinand_mem_ops {
|
||||
struct spi_mem_op reset;
|
||||
struct spi_mem_op readid;
|
||||
struct spi_mem_op wr_en;
|
||||
struct spi_mem_op wr_dis;
|
||||
struct spi_mem_op set_feature;
|
||||
struct spi_mem_op get_feature;
|
||||
struct spi_mem_op blk_erase;
|
||||
struct spi_mem_op page_read;
|
||||
struct spi_mem_op prog_exec;
|
||||
const struct spi_mem_op *read_cache;
|
||||
const struct spi_mem_op *write_cache;
|
||||
const struct spi_mem_op *update_cache;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spinand_device - SPI NAND device instance
|
||||
* @base: NAND device instance
|
||||
|
|
@ -606,10 +724,10 @@ struct spinand_dirmap {
|
|||
* @lock: lock used to serialize accesses to the NAND
|
||||
* @id: NAND ID as returned by READ_ID
|
||||
* @flags: NAND flags
|
||||
* @op_templates: various SPI mem op templates
|
||||
* @op_templates.read_cache: read cache op template
|
||||
* @op_templates.write_cache: write cache op template
|
||||
* @op_templates.update_cache: update cache op template
|
||||
* @ssdr_op_templates: Templates for all single SDR SPI mem operations
|
||||
* @odtr_op_templates: Templates for all octal DTR SPI mem operations
|
||||
* @op_templates: Templates for all SPI mem operations
|
||||
* @bus_iface: Current bus interface
|
||||
* @select_target: select a specific target/die. Usually called before sending
|
||||
* a command addressing a page or an eraseblock embedded in
|
||||
* this die. Only required if your chip exposes several dies
|
||||
|
|
@ -643,11 +761,10 @@ struct spinand_device {
|
|||
struct spinand_id id;
|
||||
u32 flags;
|
||||
|
||||
struct {
|
||||
const struct spi_mem_op *read_cache;
|
||||
const struct spi_mem_op *write_cache;
|
||||
const struct spi_mem_op *update_cache;
|
||||
} op_templates;
|
||||
struct spinand_mem_ops ssdr_op_templates;
|
||||
struct spinand_mem_ops odtr_op_templates;
|
||||
struct spinand_mem_ops *op_templates;
|
||||
enum spinand_bus_interface bus_iface;
|
||||
|
||||
struct spinand_dirmap *dirmaps;
|
||||
|
||||
|
|
@ -664,7 +781,8 @@ struct spinand_device {
|
|||
const struct spinand_manufacturer *manufacturer;
|
||||
void *priv;
|
||||
|
||||
int (*configure_chip)(struct spinand_device *spinand);
|
||||
int (*configure_chip)(struct spinand_device *spinand,
|
||||
enum spinand_bus_interface iface);
|
||||
bool cont_read_possible;
|
||||
int (*set_cont_read)(struct spinand_device *spinand,
|
||||
bool enable);
|
||||
|
|
@ -677,6 +795,14 @@ struct spinand_device {
|
|||
unsigned int retry_mode);
|
||||
};
|
||||
|
||||
struct spi_mem_op spinand_fill_wr_en_op(struct spinand_device *spinand);
|
||||
struct spi_mem_op spinand_fill_set_feature_op(struct spinand_device *spinand, u64 reg, const void *valptr);
|
||||
struct spi_mem_op spinand_fill_get_feature_op(struct spinand_device *spinand, u64 reg, void *valptr);
|
||||
struct spi_mem_op spinand_fill_prog_exec_op(struct spinand_device *spinand, u64 addr);
|
||||
|
||||
#define SPINAND_OP(spinand, op_name, ...) \
|
||||
spinand_fill_ ## op_name ## _op(spinand, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* mtd_to_spinand() - Get the SPI NAND device attached to an MTD instance
|
||||
* @mtd: MTD instance
|
||||
|
|
|
|||
|
|
@ -51,6 +51,14 @@
|
|||
.dtr = true, \
|
||||
}
|
||||
|
||||
#define SPI_MEM_DTR_OP_RPT_ADDR(__val, __buswidth) \
|
||||
{ \
|
||||
.nbytes = 2, \
|
||||
.val = __val | __val << 8, \
|
||||
.buswidth = __buswidth, \
|
||||
.dtr = true, \
|
||||
}
|
||||
|
||||
#define SPI_MEM_OP_NO_ADDR { }
|
||||
|
||||
#define SPI_MEM_OP_DUMMY(__nbytes, __buswidth) \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue