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 files changed
+1292
-608
No files matched your search
@@ -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;
|
||||
...
|
||||
};
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -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
|
||||
+346
-52
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+144
-18
@@ -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) \
|
||||
|
||||
Reference in new issue
Block a user