diff options
69 files changed, 1177 insertions, 1280 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor b/Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor index d76cd3946434..c800621eff95 100644 --- a/Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor +++ b/Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor @@ -5,6 +5,9 @@ Contact: linux-mtd@lists.infradead.org Description: (RO) The JEDEC ID of the SPI NOR flash as reported by the flash device. + The attribute is not present if the flash doesn't support + the "Read JEDEC ID" command (9Fh). This is the case for + non-JEDEC compliant flashes. What: /sys/bus/spi/devices/.../spi-nor/manufacturer Date: April 2021 @@ -12,6 +15,9 @@ KernelVersion: 5.14 Contact: linux-mtd@lists.infradead.org Description: (RO) Manufacturer of the SPI NOR flash. + The attribute is not present if the flash device isn't + known to the kernel and is only probed by its SFDP + tables. What: /sys/bus/spi/devices/.../spi-nor/partname Date: April 2021 diff --git a/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml index 4741864da48e..e7ec0c59bca6 100644 --- a/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml @@ -14,9 +14,6 @@ maintainers: - Maxime Ripard <mripard@kernel.org> properties: - "#address-cells": true - "#size-cells": true - compatible: enum: - allwinner,sun4i-a10-nand @@ -49,12 +46,8 @@ properties: dma-names: const: rxtx - pinctrl-names: true - patternProperties: - "^pinctrl-[0-9]+$": true - - "^nand@[a-f0-9]+$": + "^nand@[a-f0-9]$": type: object properties: reg: @@ -91,6 +84,29 @@ required: - clocks - clock-names -additionalProperties: false +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/clock/sun6i-rtc.h> + #include <dt-bindings/clock/sun8i-a23-a33-ccu.h> + #include <dt-bindings/reset/sun8i-a23-a33-ccu.h> + + nand-controller@1c03000 { + compatible = "allwinner,sun8i-a23-nand-controller"; + reg = <0x01c03000 0x1000>; + interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_NAND>, <&ccu CLK_NAND>; + clock-names = "ahb", "mod"; + resets = <&ccu RST_BUS_NAND>; + reset-names = "ahb"; + dmas = <&dma 5>; + dma-names = "rxtx"; + pinctrl-names = "default"; + pinctrl-0 = <&nand_pins &nand_cs0_pin &nand_rb0_pin>; + #address-cells = <1>; + #size-cells = <0>; + }; ... diff --git a/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml index f013fb976d95..d028269cdbaa 100644 --- a/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml @@ -35,9 +35,6 @@ properties: interrupts: maxItems: 1 - "#address-cells": true - "#size-cells": true - required: - compatible - reg @@ -45,7 +42,7 @@ required: - clock-names - interrupts -additionalProperties: true +unevaluatedProperties: true examples: - | diff --git a/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml b/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml index 023f3ef0fa13..e552875040e2 100644 --- a/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml +++ b/Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml @@ -34,20 +34,20 @@ unevaluatedProperties: false examples: - | smcc: memory-controller@e000e000 { - compatible = "arm,pl353-smc-r2p1", "arm,primecell"; - reg = <0xe000e000 0x0001000>; - clock-names = "memclk", "apb_pclk"; - clocks = <&clkc 11>, <&clkc 44>; - ranges = <0x0 0x0 0xe1000000 0x1000000 /* Nand CS region */ - 0x1 0x0 0xe2000000 0x2000000 /* SRAM/NOR CS0 region */ - 0x2 0x0 0xe4000000 0x2000000>; /* SRAM/NOR CS1 region */ - #address-cells = <2>; - #size-cells = <1>; - - nfc0: nand-controller@0,0 { - compatible = "arm,pl353-nand-r2p1"; - reg = <0 0 0x1000000>; - #address-cells = <1>; - #size-cells = <0>; - }; + compatible = "arm,pl353-smc-r2p1", "arm,primecell"; + reg = <0xe000e000 0x0001000>; + clock-names = "memclk", "apb_pclk"; + clocks = <&clkc 11>, <&clkc 44>; + ranges = <0x0 0x0 0xe1000000 0x1000000 /* Nand CS region */ + 0x1 0x0 0xe2000000 0x2000000 /* SRAM/NOR CS0 region */ + 0x2 0x0 0xe4000000 0x2000000>; /* SRAM/NOR CS1 region */ + #address-cells = <2>; + #size-cells = <1>; + + nfc0: nand-controller@0,0 { + compatible = "arm,pl353-nand-r2p1"; + reg = <0 0 0x1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; }; diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt index 3aa297c97ab6..50645828ac20 100644 --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt @@ -45,10 +45,8 @@ Optional properties: - atmel,rb: an integer identifying the native Ready/Busy pin. Only meaningful on sama5 SoCs. -All generic properties described in -Documentation/devicetree/bindings/mtd/{common,nand}.txt also apply to the NAND -device node, and NAND partitions should be defined under the NAND node as -described in Documentation/devicetree/bindings/mtd/partition.txt. +All generic properties are described in the generic yaml files under +Documentation/devicetree/bindings/mtd/. * ECC engine (PMECC) bindings: diff --git a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.yaml b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.yaml index dd5a64969e37..1571024aa119 100644 --- a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.yaml +++ b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.yaml @@ -86,15 +86,15 @@ properties: minItems: 1 items: - description: NAND CTLRDY interrupt - - description: FLASH_DMA_DONE if flash DMA is available - - description: FLASH_EDU_DONE if EDU is available + - description: FLASH_DMA_DONE (if flash DMA is available) or FLASH_EDU_DONE (if EDU is available) interrupt-names: minItems: 1 items: - const: nand_ctlrdy - - const: flash_dma_done - - const: flash_edu_done + - enum: + - flash_dma_done + - flash_edu_done clocks: maxItems: 1 @@ -173,6 +173,13 @@ allOf: - const: nand - const: iproc-idm - const: iproc-ext + - if: + properties: + interrupts: + minItems: 2 + then: + required: + - interrupt-names unevaluatedProperties: false @@ -184,51 +191,52 @@ required: examples: - | nand-controller@f0442800 { - compatible = "brcm,brcmnand-v7.0", "brcm,brcmnand"; - reg = <0xf0442800 0x600>, - <0xf0443000 0x100>; - reg-names = "nand", "flash-dma"; - interrupt-parent = <&hif_intr2_intc>; - interrupts = <24>, <4>; + compatible = "brcm,brcmnand-v7.0", "brcm,brcmnand"; + reg = <0xf0442800 0x600>, + <0xf0443000 0x100>; + reg-names = "nand", "flash-dma"; + interrupt-parent = <&hif_intr2_intc>; + interrupts = <24>, <4>; + interrupt-names = "nand_ctlrdy", "flash_dma_done"; + + #address-cells = <1>; + #size-cells = <0>; + + nand@1 { + compatible = "brcm,nandcs"; + reg = <1>; // Chip select 1 + nand-on-flash-bbt; + nand-ecc-strength = <12>; + nand-ecc-step-size = <512>; #address-cells = <1>; - #size-cells = <0>; - - nand@1 { - compatible = "brcm,nandcs"; - reg = <1>; // Chip select 1 - nand-on-flash-bbt; - nand-ecc-strength = <12>; - nand-ecc-step-size = <512>; - - #address-cells = <1>; - #size-cells = <1>; - }; + #size-cells = <1>; + }; }; - | nand-controller@10000200 { - compatible = "brcm,nand-bcm63168", "brcm,nand-bcm6368", - "brcm,brcmnand-v4.0", "brcm,brcmnand"; - reg = <0x10000200 0x180>, - <0x100000b0 0x10>, - <0x10000600 0x200>; - reg-names = "nand", "nand-int-base", "nand-cache"; - interrupt-parent = <&periph_intc>; - interrupts = <50>; - clocks = <&periph_clk 20>; - clock-names = "nand"; + compatible = "brcm,nand-bcm63168", "brcm,nand-bcm6368", + "brcm,brcmnand-v4.0", "brcm,brcmnand"; + reg = <0x10000200 0x180>, + <0x100000b0 0x10>, + <0x10000600 0x200>; + reg-names = "nand", "nand-int-base", "nand-cache"; + interrupt-parent = <&periph_intc>; + interrupts = <50>; + clocks = <&periph_clk 20>; + clock-names = "nand"; + + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + compatible = "brcm,nandcs"; + reg = <0>; + nand-on-flash-bbt; + nand-ecc-strength = <1>; + nand-ecc-step-size = <512>; #address-cells = <1>; - #size-cells = <0>; - - nand@0 { - compatible = "brcm,nandcs"; - reg = <0>; - nand-on-flash-bbt; - nand-ecc-strength = <1>; - nand-ecc-step-size = <512>; - - #address-cells = <1>; - #size-cells = <1>; - }; + #size-cells = <1>; + }; }; diff --git a/Documentation/devicetree/bindings/mtd/denali,nand.yaml b/Documentation/devicetree/bindings/mtd/denali,nand.yaml index 1307ed7e7fc6..0be83ad42970 100644 --- a/Documentation/devicetree/bindings/mtd/denali,nand.yaml +++ b/Documentation/devicetree/bindings/mtd/denali,nand.yaml @@ -145,6 +145,6 @@ examples: #size-cells = <0>; nand@0 { - reg = <0>; + reg = <0>; }; }; diff --git a/Documentation/devicetree/bindings/mtd/ingenic,nand.yaml b/Documentation/devicetree/bindings/mtd/ingenic,nand.yaml index 8c272c842bfd..a811a512ecc5 100644 --- a/Documentation/devicetree/bindings/mtd/ingenic,nand.yaml +++ b/Documentation/devicetree/bindings/mtd/ingenic,nand.yaml @@ -32,9 +32,9 @@ properties: partitions: type: object + deprecated: true description: Node containing description of fixed partitions. - See Documentation/devicetree/bindings/mtd/partition.txt patternProperties: "^nand@[a-f0-9]$": @@ -58,78 +58,78 @@ examples: - | #include <dt-bindings/clock/ingenic,jz4780-cgu.h> memory-controller@13410000 { - compatible = "ingenic,jz4780-nemc"; - reg = <0x13410000 0x10000>; - #address-cells = <2>; - #size-cells = <1>; - ranges = <1 0 0x1b000000 0x1000000>, - <2 0 0x1a000000 0x1000000>, - <3 0 0x19000000 0x1000000>, - <4 0 0x18000000 0x1000000>, - <5 0 0x17000000 0x1000000>, - <6 0 0x16000000 0x1000000>; - - clocks = <&cgu JZ4780_CLK_NEMC>; - - nand-controller@1 { - compatible = "ingenic,jz4780-nand"; - reg = <1 0 0x1000000>; - - #address-cells = <1>; - #size-cells = <0>; - - ecc-engine = <&bch>; - - ingenic,nemc-tAS = <10>; - ingenic,nemc-tAH = <5>; - ingenic,nemc-tBP = <10>; - ingenic,nemc-tAW = <15>; - ingenic,nemc-tSTRV = <100>; - - pinctrl-names = "default"; - pinctrl-0 = <&pins_nemc>; - - nand@1 { - reg = <1>; - - nand-ecc-step-size = <1024>; - nand-ecc-strength = <24>; - nand-ecc-mode = "hw"; - nand-on-flash-bbt; - - pinctrl-names = "default"; - pinctrl-0 = <&pins_nemc_cs1>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <2>; - #size-cells = <2>; - - partition@0 { - label = "u-boot-spl"; - reg = <0x0 0x0 0x0 0x800000>; + compatible = "ingenic,jz4780-nemc"; + reg = <0x13410000 0x10000>; + #address-cells = <2>; + #size-cells = <1>; + ranges = <1 0 0x1b000000 0x1000000>, + <2 0 0x1a000000 0x1000000>, + <3 0 0x19000000 0x1000000>, + <4 0 0x18000000 0x1000000>, + <5 0 0x17000000 0x1000000>, + <6 0 0x16000000 0x1000000>; + + clocks = <&cgu JZ4780_CLK_NEMC>; + + nand-controller@1 { + compatible = "ingenic,jz4780-nand"; + reg = <1 0 0x1000000>; + + #address-cells = <1>; + #size-cells = <0>; + + ecc-engine = <&bch>; + + ingenic,nemc-tAS = <10>; + ingenic,nemc-tAH = <5>; + ingenic,nemc-tBP = <10>; + ingenic,nemc-tAW = <15>; + ingenic,nemc-tSTRV = <100>; + + pinctrl-names = "default"; + pinctrl-0 = <&pins_nemc>; + + nand@1 { + reg = <1>; + + nand-ecc-step-size = <1024>; + nand-ecc-strength = <24>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + + pinctrl-names = "default"; + pinctrl-0 = <&pins_nemc_cs1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <2>; + #size-cells = <2>; + + partition@0 { + label = "u-boot-spl"; + reg = <0x0 0x0 0x0 0x800000>; + }; + + partition@800000 { + label = "u-boot"; + reg = <0x0 0x800000 0x0 0x200000>; + }; + + partition@a00000 { + label = "u-boot-env"; + reg = <0x0 0xa00000 0x0 0x200000>; + }; + + partition@c00000 { + label = "boot"; + reg = <0x0 0xc00000 0x0 0x4000000>; + }; + + partition@4c00000 { + label = "system"; + reg = <0x0 0x4c00000 0x1 0xfb400000>; + }; + }; }; - - partition@800000 { - label = "u-boot"; - reg = <0x0 0x800000 0x0 0x200000>; - }; - - partition@a00000 { - label = "u-boot-env"; - reg = <0x0 0xa00000 0x0 0x200000>; - }; - - partition@c00000 { - label = "boot"; - reg = <0x0 0xc00000 0x0 0x4000000>; - }; - - partition@4c00000 { - label = "system"; - reg = <0x0 0x4c00000 0x1 0xfb400000>; - }; - }; }; - }; }; diff --git a/Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml b/Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml index 741c66ee06c3..8c62c7d3d0cd 100644 --- a/Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml +++ b/Documentation/devicetree/bindings/mtd/intel,lgm-ebunand.yaml @@ -39,14 +39,8 @@ properties: - const: tx - const: rx - "#address-cells": - const: 1 - - "#size-cells": - const: 0 - patternProperties: - "^nand@[a-f0-9]+$": + "^nand@[a-f0-9]$": type: object properties: reg: @@ -67,33 +61,31 @@ required: - clocks - dmas - dma-names - - "#address-cells" - - "#size-cells" -additionalProperties: false +unevaluatedProperties: false examples: - | nand-controller@e0f00000 { - compatible = "intel,lgm-ebunand"; - reg = <0xe0f00000 0x100>, - <0xe1000000 0x300>, - <0xe1400000 0x8000>, - <0xe1c00000 0x1000>, - <0x17400000 0x4>, - <0x17c00000 0x4>; - reg-names = "ebunand", "hsnand", "nand_cs0", "nand_cs1", - "addr_sel0", "addr_sel1"; - clocks = <&cgu0 125>; - dmas = <&dma0 8>, <&dma0 9>; - dma-names = "tx", "rx"; - #address-cells = <1>; - #size-cells = <0>; - - nand@0 { - reg = <0>; - nand-ecc-mode = "hw"; - }; + compatible = "intel,lgm-ebunand"; + reg = <0xe0f00000 0x100>, + <0xe1000000 0x300>, + <0xe1400000 0x8000>, + <0xe1c00000 0x1000>, + <0x17400000 0x4>, + <0x17c00000 0x4>; + reg-names = "ebunand", "hsnand", "nand_cs0", "nand_cs1", + "addr_sel0", "addr_sel1"; + clocks = <&cgu0 125>; + dmas = <&dma0 8>, <&dma0 9>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + nand-ecc-mode = "hw"; + }; }; ... diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml index 7149784a36ac..3fe981b14e2c 100644 --- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml +++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml @@ -70,24 +70,17 @@ properties: be used on such systems, to denote the absence of a reliable reset mechanism. - partitions: - type: object - - '#address-cells': true - '#size-cells': true - -patternProperties: - # Note: use 'partitions' node for new users - '^partition@': - type: object - - "^otp(-[0-9]+)?$": - type: object + reset-gpios: + description: + A GPIO line connected to the RESET (active low) signal of the device. + If "broken-flash-reset" is present then having this property does not + make any difference. unevaluatedProperties: false examples: - | + #include <dt-bindings/gpio/gpio.h> spi { #address-cells = <1>; #size-cells = <0>; @@ -97,6 +90,7 @@ examples: reg = <0>; spi-max-frequency = <40000000>; m25p,fast-read; + reset-gpios = <&gpio 12 GPIO_ACTIVE_LOW>; }; }; ... diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt index 6d60bc3063f5..64c06aa05ac7 100644 --- a/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt +++ b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt @@ -19,7 +19,7 @@ accuracy:) - nxp,wr_low: WR_LOW Optional subnodes: -- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt +- Partitions, see Documentation/devicetree/bindings/mtd/mtd.yaml Example: diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt index d94edc0fc554..39f17630a301 100644 --- a/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt +++ b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt @@ -20,7 +20,7 @@ clock speed:) - nxp,rsetup: Read setup time (R_SETUP) Optional subnodes: -- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt +- Partitions, see Documentation/devicetree/bindings/mtd/mtd.yaml Example: diff --git a/Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml b/Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml index 8cc2a7ceb5fb..ea9450fe7c9f 100644 --- a/Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml +++ b/Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml @@ -34,13 +34,13 @@ unevaluatedProperties: false examples: - | spi { - #address-cells = <1>; - #size-cells = <0>; - - eeram@0 { - compatible = "microchip,48l640"; - reg = <0>; - spi-max-frequency = <20000000>; - }; + #address-cells = <1>; + #size-cells = <0>; + + eeram@0 { + compatible = "microchip,48l640"; + reg = <0>; + spi-max-frequency = <20000000>; + }; }; ... diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.yaml b/Documentation/devicetree/bindings/mtd/mtd-physmap.yaml index 82eb4e0f453b..5df94953c34e 100644 --- a/Documentation/devicetree/bindings/mtd/mtd-physmap.yaml +++ b/Documentation/devicetree/bindings/mtd/mtd-physmap.yaml @@ -13,6 +13,9 @@ description: | Flash chips (Memory Technology Devices) are often used for solid state file systems on embedded devices. +allOf: + - $ref: "mtd.yaml#" + properties: compatible: oneOf: @@ -121,10 +124,6 @@ properties: big-endian: true little-endian: true -patternProperties: - '@[0-9a-f]+$': - $ref: partitions/partition.yaml - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/mtd/mtd.yaml b/Documentation/devicetree/bindings/mtd/mtd.yaml index 3498e485679b..78da129e9985 100644 --- a/Documentation/devicetree/bindings/mtd/mtd.yaml +++ b/Documentation/devicetree/bindings/mtd/mtd.yaml @@ -12,7 +12,7 @@ maintainers: properties: $nodename: - pattern: "^flash(@.*)?$" + pattern: "^(flash|.*sram)(@.*)?$" label: description: @@ -21,9 +21,28 @@ properties: based name) in order to ease flash device identification and/or describe what they are used for. + '#address-cells': + deprecated: true + + '#size-cells': + deprecated: true + + partitions: + $ref: /schemas/mtd/partitions/partitions.yaml + + required: + - compatible + patternProperties: + "@[0-9a-f]+$": + $ref: partitions/partition.yaml + deprecated: true + + "^partition@[0-9a-f]+": + $ref: partitions/partition.yaml + deprecated: true + "^otp(-[0-9]+)?$": - type: object $ref: ../nvmem/nvmem.yaml# description: | @@ -40,6 +59,7 @@ patternProperties: required: - compatible +# This is a generic file other binding inherit from additionalProperties: true examples: diff --git a/Documentation/devicetree/bindings/mtd/mtk-nand.txt b/Documentation/devicetree/bindings/mtd/mtk-nand.txt index 4d3ec5e4ff8a..839ea2f93d04 100644 --- a/Documentation/devicetree/bindings/mtd/mtk-nand.txt +++ b/Documentation/devicetree/bindings/mtd/mtk-nand.txt @@ -131,7 +131,7 @@ Example: }; NAND chip optional subnodes: -- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt +- Partitions, see Documentation/devicetree/bindings/mtd/mtd.yaml Example: nand@0 { diff --git a/Documentation/devicetree/bindings/mtd/nand-chip.yaml b/Documentation/devicetree/bindings/mtd/nand-chip.yaml index 97ac3a3fbb52..6e2dc025d694 100644 --- a/Documentation/devicetree/bindings/mtd/nand-chip.yaml +++ b/Documentation/devicetree/bindings/mtd/nand-chip.yaml @@ -9,6 +9,9 @@ title: NAND Chip and NAND Controller Generic Binding maintainers: - Miquel Raynal <miquel.raynal@bootlin.com> +allOf: + - $ref: "mtd.yaml#" + description: | This file covers the generic description of a NAND chip. It implies that the bus interface should not be taken into account: both raw NAND devices and @@ -67,4 +70,5 @@ properties: required: - reg +# This file can be referenced by more specific devices (like spi-nands) additionalProperties: true diff --git a/Documentation/devicetree/bindings/mtd/nand-controller.yaml b/Documentation/devicetree/bindings/mtd/nand-controller.yaml index 359a015d4e5a..220aa2c8c0b5 100644 --- a/Documentation/devicetree/bindings/mtd/nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/nand-controller.yaml @@ -51,7 +51,6 @@ properties: patternProperties: "^nand@[a-f0-9]$": - type: object $ref: "nand-chip.yaml#" properties: @@ -130,6 +129,7 @@ required: - "#address-cells" - "#size-cells" +# This is a generic file other binding inherit from and extend additionalProperties: true examples: diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt deleted file mode 100644 index ead90e8274d6..000000000000 --- a/Documentation/devicetree/bindings/mtd/partition.txt +++ /dev/null @@ -1,33 +0,0 @@ -Flash partitions in device tree -=============================== - -Flash devices can be partitioned into one or more functional ranges (e.g. "boot -code", "nvram", "kernel"). - -Different devices may be partitioned in a different ways. Some may use a fixed -flash layout set at production time. Some may use on-flash table that describes -the geometry and naming/purpose of each functional region. It is also possible -to see these methods mixed. - -To assist system software in locating partitions, we allow describing which -method is used for a given flash device. To describe the method there should be -a subnode of the flash device that is named 'partitions'. It must have a -'compatible' property, which is used to identify the method to use. - -When a single partition is represented with a DT node (it depends on a used -format) it may also be described using above rules ('compatible' and optionally -some extra properties / subnodes). It allows describing more complex, -hierarchical (multi-level) layouts and should be used if there is some -significant relation between partitions or some partition internally uses -another partitioning method. - -Available bindings are listed in the "partitions" subdirectory. - - -Deprecated: partitions defined in flash node -============================================ - -For backwards compatibility partitions as direct subnodes of the flash device are -supported. This use is discouraged. -NOTE: also for backwards compatibility, direct subnodes that have a compatible -string are not considered partitions, as they may be used for other bindings. diff --git a/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml b/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml index 76c88027b6d2..97618847ee35 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml @@ -9,6 +9,8 @@ title: ARM Firmware Suite (AFS) Partitions maintainers: - Linus Walleij <linus.walleij@linaro.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, diff --git a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml index 7b113e5e3421..5bbb1c01ddee 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml @@ -17,6 +17,8 @@ description: | maintainers: - Rafał Miłecki <rafal@milecki.pl> +select: false + properties: compatible: const: brcm,bcm4908-partitions diff --git a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.yaml index 3484e06d6bcb..939e7b50db22 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.yaml @@ -35,6 +35,8 @@ description: | maintainers: - Rafał Miłecki <rafal@milecki.pl> +select: false + properties: compatible: const: brcm,bcm947xx-cfe-partitions diff --git a/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml index ad3ccd250802..331e564f29dc 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml @@ -31,24 +31,17 @@ properties: patternProperties: "@[0-9a-f]+$": - allOf: - - $ref: "partition.yaml#" - - if: - properties: - compatible: - contains: - const: sercomm,sc-partitions - then: - 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# + + 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 required: - "#address-cells" @@ -84,6 +77,7 @@ examples: partition@0 { label = "filesystem"; reg = <0x00000000 0x1 0x00000000>; + linux,rootfs; }; }; diff --git a/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml index 99249cdfbfb3..213858f60375 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml @@ -18,6 +18,8 @@ description: | maintainers: - Rafał Miłecki <rafal@milecki.pl> +select: false + properties: compatible: const: linksys,ns-partitions diff --git a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml index 5cdd2efa9132..5474d63268dc 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml @@ -17,6 +17,7 @@ maintainers: - Ansuel Smith <ansuelsmth@gmail.com> allOf: + - $ref: /schemas/mtd/partitions/partition.yaml# - $ref: /schemas/nvmem/nvmem.yaml# properties: @@ -26,7 +27,7 @@ properties: required: - compatible -additionalProperties: true +unevaluatedProperties: false examples: - | @@ -84,7 +85,6 @@ examples: compatible = "nvmem-cells"; label = "calibration"; reg = <0xf00000 0x100000>; - ranges = <0 0xf00000 0x100000>; #address-cells = <1>; #size-cells = <1>; diff --git a/Documentation/devicetree/bindings/mtd/partitions/partition.yaml b/Documentation/devicetree/bindings/mtd/partitions/partition.yaml index f1a02d840b12..cdffbb9cedc2 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/partition.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/partition.yaml @@ -52,6 +52,10 @@ properties: immune to paired-pages corruptions type: boolean + linux,rootfs: + description: Marks partition that contains root filesystem to mount and boot + user space from + if: not: required: [ reg ] @@ -60,4 +64,5 @@ then: $nodename: pattern: '^partition-.*$' +# This is a generic file other binding inherit from and extend additionalProperties: true diff --git a/Documentation/devicetree/bindings/mtd/partitions/partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/partitions.yaml new file mode 100644 index 000000000000..9aca4e6c6047 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/partitions/partitions.yaml @@ -0,0 +1,41 @@ +# 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 + +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 diff --git a/Documentation/devicetree/bindings/mtd/partitions/qcom,smem-part.yaml b/Documentation/devicetree/bindings/mtd/partitions/qcom,smem-part.yaml index dc07909af023..61d12bda356e 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/qcom,smem-part.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/qcom,smem-part.yaml @@ -15,13 +15,15 @@ description: | varies between partition table revisions. V3 supports maximum 16 partitions and V4 supports 48 partitions. +select: false + properties: compatible: const: qcom,smem-part patternProperties: "^partition-[0-9a-z]+$": - $ref: partition.yaml# + $ref: nvmem-cells.yaml required: - compatible @@ -39,22 +41,22 @@ examples: - | /* Example declaring dynamic partition */ flash { - partitions { - compatible = "qcom,smem-part"; - - partition-art { - compatible = "nvmem-cells"; - #address-cells = <1>; - #size-cells = <1>; - label = "0:art"; - - macaddr_art_0: macaddr@0 { - reg = <0x0 0x6>; - }; - - macaddr_art_6: macaddr@6 { - reg = <0x6 0x6>; - }; + partitions { + compatible = "qcom,smem-part"; + + partition-art { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + label = "0:art"; + + macaddr_art_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_art_6: macaddr@6 { + reg = <0x6 0x6>; + }; + }; }; - }; }; diff --git a/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml b/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml index fee8d81b5276..ba7445cd69e8 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/redboot-fis.yaml @@ -16,6 +16,8 @@ description: The FLASH Image System (FIS) directory is a flash description maintainers: - Linus Walleij <linus.walleij@linaro.org> +select: false + properties: compatible: const: redboot-fis @@ -26,6 +28,10 @@ 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 diff --git a/Documentation/devicetree/bindings/mtd/partitions/tplink,safeloader-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/tplink,safeloader-partitions.yaml new file mode 100644 index 000000000000..a24bbaac3a90 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/partitions/tplink,safeloader-partitions.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/partitions/tplink,safeloader-partitions.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TP-Link SafeLoader partitions + +description: | + TP-Link home routers store various data on flash (e.g. bootloader, + flash layout, firmware, product info, configuration, calibration + data). That requires flash partitioning. + + Flash space layout of TP-Link devices is stored on flash itself using + a custom ASCII-based format. That format was first found in TP-Link + devices with a custom SafeLoader bootloader. Later it was adapted to + CFE and U-Boot bootloaders. + + Partitions specified in partitions table cover whole flash space. Some + contain static data that shouldn't get modified (device's MAC or WiFi + calibration data). Others are semi-static (like kernel). Finally some + partitions contain fully changeable content (like rootfs). + + This binding describes partitioning method and defines offset of ASCII + based partitions table. That offset is picked at manufacturing process + and doesn't change. + +maintainers: + - Rafał Miłecki <rafal@milecki.pl> + +properties: + compatible: + const: tplink,safeloader-partitions + + partitions-table-offset: + description: Flash offset of partitions table + $ref: /schemas/types.yaml#/definitions/uint32 + +patternProperties: + "^partition-.*$": + $ref: partition.yaml# + +required: + - partitions-table-offset + +additionalProperties: false + +examples: + - | + partitions { + compatible = "tplink,safeloader-partitions"; + partitions-table-offset = <0x100000>; + + partition-file-system { + linux,rootfs; + }; + }; diff --git a/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml index 482a2c068740..07024ee45951 100644 --- a/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml +++ b/Documentation/devicetree/bindings/mtd/qcom,nandc.yaml @@ -31,9 +31,6 @@ properties: - const: core - const: aon - "#address-cells": true - "#size-cells": true - patternProperties: "^nand@[a-f0-9]$": type: object @@ -139,85 +136,85 @@ examples: - | #include <dt-bindings/clock/qcom,gcc-ipq806x.h> nand-controller@1ac00000 { - compatible = "qcom,ipq806x-nand"; - reg = <0x1ac00000 0x800>; + compatible = "qcom,ipq806x-nand"; + reg = <0x1ac00000 0x800>; - clocks = <&gcc EBI2_CLK>, - <&gcc EBI2_AON_CLK>; - clock-names = "core", "aon"; + clocks = <&gcc EBI2_CLK>, + <&gcc EBI2_AON_CLK>; + clock-names = "core", "aon"; - dmas = <&adm_dma 3>; - dma-names = "rxtx"; - qcom,cmd-crci = <15>; - qcom,data-crci = <3>; + dmas = <&adm_dma 3>; + dma-names = "rxtx"; + qcom,cmd-crci = <15>; + qcom,data-crci = <3>; - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; - nand@0 { - reg = <0>; + nand@0 { + reg = <0>; - nand-ecc-strength = <4>; - nand-bus-width = <8>; + nand-ecc-strength = <4>; + nand-bus-width = <8>; - qcom,boot-partitions = <0x0 0x58a0000>; + qcom,boot-partitions = <0x0 0x58a0000>; - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; - partition@0 { - label = "boot-nand"; - reg = <0 0x58a0000>; - }; + partition@0 { + label = "boot-nand"; + reg = <0 0x58a0000>; + }; - partition@58a0000 { - label = "fs-nand"; - reg = <0x58a0000 0x4000000>; - }; + partition@58a0000 { + label = "fs-nand"; + reg = <0x58a0000 0x4000000>; + }; + }; }; - }; }; #include <dt-bindings/clock/qcom,gcc-ipq4019.h> nand-controller@79b0000 { - compatible = "qcom,ipq4019-nand"; - reg = <0x79b0000 0x1000>; - - clocks = <&gcc GCC_QPIC_CLK>, - <&gcc GCC_QPIC_AHB_CLK>; - clock-names = "core", "aon"; - - dmas = <&qpicbam 0>, - <&qpicbam 1>, - <&qpicbam 2>; - dma-names = "tx", "rx", "cmd"; - - #address-cells = <1>; - #size-cells = <0>; - - nand@0 { - reg = <0>; - nand-ecc-strength = <4>; - nand-bus-width = <8>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "boot-nand"; - reg = <0 0x58a0000>; - }; - - partition@58a0000 { - label = "fs-nand"; - reg = <0x58a0000 0x4000000>; - }; + compatible = "qcom,ipq4019-nand"; + reg = <0x79b0000 0x1000>; + + clocks = <&gcc GCC_QPIC_CLK>, + <&gcc GCC_QPIC_AHB_CLK>; + clock-names = "core", "aon"; + + dmas = <&qpicbam 0>, + <&qpicbam 1>, + <&qpicbam 2>; + dma-names = "tx", "rx", "cmd"; + + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + nand-ecc-strength = <4>; + nand-bus-width = <8>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "boot-nand"; + reg = <0 0x58a0000>; + }; + + partition@58a0000 { + label = "fs-nand"; + reg = <0x58a0000 0x4000000>; + }; + }; }; - }; }; ... diff --git a/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml index d681a4676f06..566f330851f7 100644 --- a/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml @@ -19,7 +19,9 @@ properties: - const: rockchip,rk2928-nfc - const: rockchip,rv1108-nfc - items: - - const: rockchip,rk3036-nfc + - enum: + - rockchip,rk3036-nfc + - rockchip,rk3128-nfc - const: rockchip,rk2928-nfc - items: - const: rockchip,rk3308-nfc diff --git a/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml b/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml index eab8ea3da1fa..8cbfa1504a0f 100644 --- a/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml @@ -101,31 +101,32 @@ examples: #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/clock/stm32mp1-clks.h> #include <dt-bindings/reset/stm32mp1-resets.h> + nand-controller@58002000 { - compatible = "st,stm32mp15-fmc2"; - reg = <0x58002000 0x1000>, - <0x80000000 0x1000>, - <0x88010000 0x1000>, - <0x88020000 0x1000>, - <0x81000000 0x1000>, - <0x89010000 0x1000>, - <0x89020000 0x1000>; - interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>; - dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0>, - <&mdma1 20 0x2 0x12000a08 0x0 0x0>, - <&mdma1 21 0x2 0x12000a0a 0x0 0x0>; - dma-names = "tx", "rx", "ecc"; - clocks = <&rcc FMC_K>; - resets = <&rcc FMC_R>; - #address-cells = <1>; - #size-cells = <0>; - - nand@0 { - reg = <0>; - nand-on-flash-bbt; + compatible = "st,stm32mp15-fmc2"; + reg = <0x58002000 0x1000>, + <0x80000000 0x1000>, + <0x88010000 0x1000>, + <0x88020000 0x1000>, + <0x81000000 0x1000>, + <0x89010000 0x1000>, + <0x89020000 0x1000>; + interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0>, + <&mdma1 20 0x2 0x12000a08 0x0 0x0>, + <&mdma1 21 0x2 0x12000a0a 0x0 0x0>; + dma-names = "tx", "rx", "ecc"; + clocks = <&rcc FMC_K>; + resets = <&rcc FMC_R>; #address-cells = <1>; - #size-cells = <1>; - }; + #size-cells = <0>; + + nand@0 { + reg = <0>; + nand-on-flash-bbt; + #address-cells = <1>; + #size-cells = <1>; + }; }; ... diff --git a/Documentation/devicetree/bindings/mtd/ti,am654-hbmc.yaml b/Documentation/devicetree/bindings/mtd/ti,am654-hbmc.yaml index 30b458c41cac..4774c92e7fc4 100644 --- a/Documentation/devicetree/bindings/mtd/ti,am654-hbmc.yaml +++ b/Documentation/devicetree/bindings/mtd/ti,am654-hbmc.yaml @@ -44,26 +44,26 @@ additionalProperties: false examples: - | bus { - #address-cells = <2>; - #size-cells = <2>; - - hbmc: memory-controller@47034000 { - compatible = "ti,am654-hbmc"; - reg = <0x0 0x47034000 0x0 0x100>, - <0x5 0x00000000 0x1 0x0000000>; - ranges = <0x0 0x0 0x5 0x00000000 0x4000000>, /* CS0 - 64MB */ - <0x1 0x0 0x5 0x04000000 0x4000000>; /* CS1 - 64MB */ - clocks = <&k3_clks 102 0>; #address-cells = <2>; - #size-cells = <1>; - power-domains = <&k3_pds 55>; - mux-controls = <&hbmc_mux 0>; + #size-cells = <2>; - flash@0,0 { - compatible = "cypress,hyperflash", "cfi-flash"; - reg = <0x0 0x0 0x4000000>; - #address-cells = <1>; + hbmc: memory-controller@47034000 { + compatible = "ti,am654-hbmc"; + reg = <0x0 0x47034000 0x0 0x100>, + <0x5 0x00000000 0x1 0x0000000>; + ranges = <0x0 0x0 0x5 0x00000000 0x4000000>, /* CS0 - 64MB */ + <0x1 0x0 0x5 0x04000000 0x4000000>; /* CS1 - 64MB */ + clocks = <&k3_clks 102 0>; + #address-cells = <2>; #size-cells = <1>; + power-domains = <&k3_pds 55>; + mux-controls = <&hbmc_mux 0>; + + flash@0,0 { + compatible = "cypress,hyperflash", "cfi-flash"; + reg = <0x0 0x0 0x4000000>; + #address-cells = <1>; + #size-cells = <1>; + }; }; - }; }; diff --git a/Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml b/Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml index a953f7397c40..8a79ad300216 100644 --- a/Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml +++ b/Documentation/devicetree/bindings/mtd/ti,gpmc-onenand.yaml @@ -15,6 +15,9 @@ description: as child nodes of the GPMC controller. properties: + $nodename: + pattern: "^onenand@[0-9],[0,9]$" + compatible: const: ti,omap2-onenand diff --git a/MAINTAINERS b/MAINTAINERS index 6d766c5fb2cc..de46dc69922a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13464,7 +13464,7 @@ MESON NAND CONTROLLER DRIVER FOR AMLOGIC SOCS M: Liang Yang <liang.yang@amlogic.com> L: linux-mtd@lists.infradead.org S: Maintained -F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.txt +F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml F: drivers/mtd/nand/raw/meson_* MESON VIDEO DECODER DRIVER FOR AMLOGIC SOCS diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 79cb981ececc..ff2f9e55ef28 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -136,14 +136,6 @@ config MTD_PHRAM doesn't have access to, memory beyond the mem=xxx limit, nvram, memory on the video card, etc... -config MTD_LART - tristate "28F160xx flash driver for LART" - depends on SA1100_LART - help - This enables the flash driver for LART. Please note that you do - not need any mapping/chip driver for LART. This one does it all - for you, so go disable all of those if you enabled some of them (: - config MTD_MTDRAM tristate "Test driver using RAM" help diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index 0362cf6bdc67..d11eb2b8b6f8 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_MTD_PHRAM) += phram.o obj-$(CONFIG_MTD_PMC551) += pmc551.o obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o obj-$(CONFIG_MTD_MTDRAM) += mtdram.o -obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_MCHP23K256) += mchp23k256.o diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c deleted file mode 100644 index aecd441e4183..000000000000 --- a/drivers/mtd/devices/lart.c +++ /dev/null @@ -1,682 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -/* - * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. - * - * Author: Abraham vd Merwe <abraham@2d3d.co.za> - * - * Copyright (c) 2001, 2d3D, Inc. - * - * References: - * - * [1] 3 Volt Fast Boot Block Flash Memory" Intel Datasheet - * - Order Number: 290644-005 - * - January 2000 - * - * [2] MTD internal API documentation - * - http://www.linux-mtd.infradead.org/ - * - * Limitations: - * - * Even though this driver is written for 3 Volt Fast Boot - * Block Flash Memory, it is rather specific to LART. With - * Minor modifications, notably the without data/address line - * mangling and different bus settings, etc. it should be - * trivial to adapt to other platforms. - * - * If somebody would sponsor me a different board, I'll - * adapt the driver (: - */ - -/* debugging */ -//#define LART_DEBUG - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> - -#ifndef CONFIG_SA1100_LART -#error This is for LART architecture only -#endif - -static char module_name[] = "lart"; - -/* - * These values is specific to 28Fxxxx3 flash memory. - * See section 2.3.1 in "3 Volt Fast Boot Block Flash Memory" Intel Datasheet - */ -#define FLASH_BLOCKSIZE_PARAM (4096 * BUSWIDTH) -#define FLASH_NUMBLOCKS_16m_PARAM 8 -#define FLASH_NUMBLOCKS_8m_PARAM 8 - -/* - * These values is specific to 28Fxxxx3 flash memory. - * See section 2.3.2 in "3 Volt Fast Boot Block Flash Memory" Intel Datasheet - */ -#define FLASH_BLOCKSIZE_MAIN (32768 * BUSWIDTH) -#define FLASH_NUMBLOCKS_16m_MAIN 31 -#define FLASH_NUMBLOCKS_8m_MAIN 15 - -/* - * These values are specific to LART - */ - -/* general */ -#define BUSWIDTH 4 /* don't change this - a lot of the code _will_ break if you change this */ -#define FLASH_OFFSET 0xe8000000 /* see linux/arch/arm/mach-sa1100/lart.c */ - -/* blob */ -#define NUM_BLOB_BLOCKS FLASH_NUMBLOCKS_16m_PARAM -#define PART_BLOB_START 0x00000000 -#define PART_BLOB_LEN (NUM_BLOB_BLOCKS * FLASH_BLOCKSIZE_PARAM) - -/* kernel */ -#define NUM_KERNEL_BLOCKS 7 -#define PART_KERNEL_START (PART_BLOB_START + PART_BLOB_LEN) -#define PART_KERNEL_LEN (NUM_KERNEL_BLOCKS * FLASH_BLOCKSIZE_MAIN) - -/* initial ramdisk */ -#define NUM_INITRD_BLOCKS 24 -#define PART_INITRD_START (PART_KERNEL_START + PART_KERNEL_LEN) -#define PART_INITRD_LEN (NUM_INITRD_BLOCKS * FLASH_BLOCKSIZE_MAIN) - -/* - * See section 4.0 in "3 Volt Fast Boot Block Flash Memory" Intel Datasheet - */ -#define READ_ARRAY 0x00FF00FF /* Read Array/Reset */ -#define READ_ID_CODES 0x00900090 /* Read Identifier Codes */ -#define ERASE_SETUP 0x00200020 /* Block Erase */ -#define ERASE_CONFIRM 0x00D000D0 /* Block Erase and Program Resume */ -#define PGM_SETUP 0x00400040 /* Program */ -#define STATUS_READ 0x00700070 /* Read Status Register */ -#define STATUS_CLEAR 0x00500050 /* Clear Status Register */ -#define STATUS_BUSY 0x00800080 /* Write State Machine Status (WSMS) */ -#define STATUS_ERASE_ERR 0x00200020 /* Erase Status (ES) */ -#define STATUS_PGM_ERR 0x00100010 /* Program Status (PS) */ - -/* - * See section 4.2 in "3 Volt Fast Boot Block Flash Memory" Intel Datasheet - */ -#define FLASH_MANUFACTURER 0x00890089 -#define FLASH_DEVICE_8mbit_TOP 0x88f188f1 -#define FLASH_DEVICE_8mbit_BOTTOM 0x88f288f2 -#define FLASH_DEVICE_16mbit_TOP 0x88f388f3 -#define FLASH_DEVICE_16mbit_BOTTOM 0x88f488f4 - -/***************************************************************************************************/ - -/* - * The data line mapping on LART is as follows: - * - * U2 CPU | U3 CPU - * ------------------- - * 0 20 | 0 12 - * 1 22 | 1 14 - * 2 19 | 2 11 - * 3 17 | 3 9 - * 4 24 | 4 0 - * 5 26 | 5 2 - * 6 31 | 6 7 - * 7 29 | 7 5 - * 8 21 | 8 13 - * 9 23 | 9 15 - * 10 18 | 10 10 - * 11 16 | 11 8 - * 12 25 | 12 1 - * 13 27 | 13 3 - * 14 30 | 14 6 - * 15 28 | 15 4 - */ - -/* Mangle data (x) */ -#define DATA_TO_FLASH(x) \ - ( \ - (((x) & 0x08009000) >> 11) + \ - (((x) & 0x00002000) >> 10) + \ - (((x) & 0x04004000) >> 8) + \ - (((x) & 0x00000010) >> 4) + \ - (((x) & 0x91000820) >> 3) + \ - (((x) & 0x22080080) >> 2) + \ - ((x) & 0x40000400) + \ - (((x) & 0x00040040) << 1) + \ - (((x) & 0x00110000) << 4) + \ - (((x) & 0x00220100) << 5) + \ - (((x) & 0x00800208) << 6) + \ - (((x) & 0x00400004) << 9) + \ - (((x) & 0x00000001) << 12) + \ - (((x) & 0x00000002) << 13) \ - ) - -/* Unmangle data (x) */ -#define FLASH_TO_DATA(x) \ - ( \ - (((x) & 0x00010012) << 11) + \ - (((x) & 0x00000008) << 10) + \ - (((x) & 0x00040040) << 8) + \ - (((x) & 0x00000001) << 4) + \ - (((x) & 0x12200104) << 3) + \ - (((x) & 0x08820020) << 2) + \ - ((x) & 0x40000400) + \ - (((x) & 0x00080080) >> 1) + \ - (((x) & 0x01100000) >> 4) + \ - (((x) & 0x04402000) >> 5) + \ - (((x) & 0x20008200) >> 6) + \ - (((x) & 0x80000800) >> 9) + \ - (((x) & 0x00001000) >> 12) + \ - (((x) & 0x00004000) >> 13) \ - ) - -/* - * The address line mapping on LART is as follows: - * - * U3 CPU | U2 CPU - * ------------------- - * 0 2 | 0 2 - * 1 3 | 1 3 - * 2 9 | 2 9 - * 3 13 | 3 8 - * 4 8 | 4 7 - * 5 12 | 5 6 - * 6 11 | 6 5 - * 7 10 | 7 4 - * 8 4 | 8 10 - * 9 5 | 9 11 - * 10 6 | 10 12 - * 11 7 | 11 13 - * - * BOOT BLOCK BOUNDARY - * - * 12 15 | 12 15 - * 13 14 | 13 14 - * 14 16 | 14 16 - * - * MAIN BLOCK BOUNDARY - * - * 15 17 | 15 18 - * 16 18 | 16 17 - * 17 20 | 17 20 - * 18 19 | 18 19 - * 19 21 | 19 21 - * - * As we can see from above, the addresses aren't mangled across - * block boundaries, so we don't need to worry about address - * translations except for sending/reading commands during - * initialization - */ - -/* Mangle address (x) on chip U2 */ -#define ADDR_TO_FLASH_U2(x) \ - ( \ - (((x) & 0x00000f00) >> 4) + \ - (((x) & 0x00042000) << 1) + \ - (((x) & 0x0009c003) << 2) + \ - (((x) & 0x00021080) << 3) + \ - (((x) & 0x00000010) << 4) + \ - (((x) & 0x00000040) << 5) + \ - (((x) & 0x00000024) << 7) + \ - (((x) & 0x00000008) << 10) \ - ) - -/* Unmangle address (x) on chip U2 */ -#define FLASH_U2_TO_ADDR(x) \ - ( \ - (((x) << 4) & 0x00000f00) + \ - (((x) >> 1) & 0x00042000) + \ - (((x) >> 2) & 0x0009c003) + \ - (((x) >> 3) & 0x00021080) + \ - (((x) >> 4) & 0x00000010) + \ - (((x) >> 5) & 0x00000040) + \ - (((x) >> 7) & 0x00000024) + \ - (((x) >> 10) & 0x00000008) \ - ) - -/* Mangle address (x) on chip U3 */ -#define ADDR_TO_FLASH_U3(x) \ - ( \ - (((x) & 0x00000080) >> 3) + \ - (((x) & 0x00000040) >> 1) + \ - (((x) & 0x00052020) << 1) + \ - (((x) & 0x00084f03) << 2) + \ - (((x) & 0x00029010) << 3) + \ - (((x) & 0x00000008) << 5) + \ - (((x) & 0x00000004) << 7) \ - ) - -/* Unmangle address (x) on chip U3 */ -#define FLASH_U3_TO_ADDR(x) \ - ( \ - (((x) << 3) & 0x00000080) + \ - (((x) << 1) & 0x00000040) + \ - (((x) >> 1) & 0x00052020) + \ - (((x) >> 2) & 0x00084f03) + \ - (((x) >> 3) & 0x00029010) + \ - (((x) >> 5) & 0x00000008) + \ - (((x) >> 7) & 0x00000004) \ - ) - -/***************************************************************************************************/ - -static __u8 read8 (__u32 offset) -{ - volatile __u8 *data = (__u8 *) (FLASH_OFFSET + offset); -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.2x\n", __func__, offset, *data); -#endif - return (*data); -} - -static __u32 read32 (__u32 offset) -{ - volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset); -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.8x\n", __func__, offset, *data); -#endif - return (*data); -} - -static void write32 (__u32 x,__u32 offset) -{ - volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset); - *data = x; -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n", __func__, offset, *data); -#endif -} - -/***************************************************************************************************/ - -/* - * Probe for 16mbit flash memory on a LART board without doing - * too much damage. Since we need to write 1 dword to memory, - * we're f**cked if this happens to be DRAM since we can't - * restore the memory (otherwise we might exit Read Array mode). - * - * Returns 1 if we found 16mbit flash memory on LART, 0 otherwise. - */ -static int flash_probe (void) -{ - __u32 manufacturer,devtype; - - /* setup "Read Identifier Codes" mode */ - write32 (DATA_TO_FLASH (READ_ID_CODES),0x00000000); - - /* probe U2. U2/U3 returns the same data since the first 3 - * address lines is mangled in the same way */ - manufacturer = FLASH_TO_DATA (read32 (ADDR_TO_FLASH_U2 (0x00000000))); - devtype = FLASH_TO_DATA (read32 (ADDR_TO_FLASH_U2 (0x00000001))); - - /* put the flash back into command mode */ - write32 (DATA_TO_FLASH (READ_ARRAY),0x00000000); - - return (manufacturer == FLASH_MANUFACTURER && (devtype == FLASH_DEVICE_16mbit_TOP || devtype == FLASH_DEVICE_16mbit_BOTTOM)); -} - -/* - * Erase one block of flash memory at offset ``offset'' which is any - * address within the block which should be erased. - * - * Returns 1 if successful, 0 otherwise. - */ -static inline int erase_block (__u32 offset) -{ - __u32 status; - -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(): 0x%.8x\n", __func__, offset); -#endif - - /* erase and confirm */ - write32 (DATA_TO_FLASH (ERASE_SETUP),offset); - write32 (DATA_TO_FLASH (ERASE_CONFIRM),offset); - - /* wait for block erase to finish */ - do - { - write32 (DATA_TO_FLASH (STATUS_READ),offset); - status = FLASH_TO_DATA (read32 (offset)); - } - while ((~status & STATUS_BUSY) != 0); - - /* put the flash back into command mode */ - write32 (DATA_TO_FLASH (READ_ARRAY),offset); - - /* was the erase successful? */ - if ((status & STATUS_ERASE_ERR)) - { - printk (KERN_WARNING "%s: erase error at address 0x%.8x.\n",module_name,offset); - return (0); - } - - return (1); -} - -static int flash_erase (struct mtd_info *mtd,struct erase_info *instr) -{ - __u32 addr,len; - int i,first; - -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n", __func__, instr->addr, instr->len); -#endif - - /* - * check that both start and end of the requested erase are - * aligned with the erasesize at the appropriate addresses. - * - * skip all erase regions which are ended before the start of - * the requested erase. Actually, to save on the calculations, - * we skip to the first erase region which starts after the - * start of the requested erase, and then go back one. - */ - for (i = 0; i < mtd->numeraseregions && instr->addr >= mtd->eraseregions[i].offset; i++) ; - i--; - - /* - * ok, now i is pointing at the erase region in which this - * erase request starts. Check the start of the requested - * erase range is aligned with the erase size which is in - * effect here. - */ - if (i < 0 || (instr->addr & (mtd->eraseregions[i].erasesize - 1))) - return -EINVAL; - - /* Remember the erase region we start on */ - first = i; - - /* - * next, check that the end of the requested erase is aligned - * with the erase region at that address. - * - * as before, drop back one to point at the region in which - * the address actually falls - */ - for (; i < mtd->numeraseregions && instr->addr + instr->len >= mtd->eraseregions[i].offset; i++) ; - i--; - - /* is the end aligned on a block boundary? */ - if (i < 0 || ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1))) - return -EINVAL; - - addr = instr->addr; - len = instr->len; - - i = first; - - /* now erase those blocks */ - while (len) - { - if (!erase_block (addr)) - return (-EIO); - - addr += mtd->eraseregions[i].erasesize; - len -= mtd->eraseregions[i].erasesize; - - if (addr == mtd->eraseregions[i].offset + (mtd->eraseregions[i].erasesize * mtd->eraseregions[i].numblocks)) i++; - } - - return (0); -} - -static int flash_read (struct mtd_info *mtd,loff_t from,size_t len,size_t *retlen,u_char *buf) -{ -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n", __func__, (__u32)from, len); -#endif - - /* we always read len bytes */ - *retlen = len; - - /* first, we read bytes until we reach a dword boundary */ - if (from & (BUSWIDTH - 1)) - { - int gap = BUSWIDTH - (from & (BUSWIDTH - 1)); - - while (len && gap--) { - *buf++ = read8 (from++); - len--; - } - } - - /* now we read dwords until we reach a non-dword boundary */ - while (len >= BUSWIDTH) - { - *((__u32 *) buf) = read32 (from); - - buf += BUSWIDTH; - from += BUSWIDTH; - len -= BUSWIDTH; - } - - /* top up the last unaligned bytes */ - if (len & (BUSWIDTH - 1)) - while (len--) *buf++ = read8 (from++); - - return (0); -} - -/* - * Write one dword ``x'' to flash memory at offset ``offset''. ``offset'' - * must be 32 bits, i.e. it must be on a dword boundary. - * - * Returns 1 if successful, 0 otherwise. - */ -static inline int write_dword (__u32 offset,__u32 x) -{ - __u32 status; - -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n", __func__, offset, x); -#endif - - /* setup writing */ - write32 (DATA_TO_FLASH (PGM_SETUP),offset); - - /* write the data */ - write32 (x,offset); - - /* wait for the write to finish */ - do - { - write32 (DATA_TO_FLASH (STATUS_READ),offset); - status = FLASH_TO_DATA (read32 (offset)); - } - while ((~status & STATUS_BUSY) != 0); - - /* put the flash back into command mode */ - write32 (DATA_TO_FLASH (READ_ARRAY),offset); - - /* was the write successful? */ - if ((status & STATUS_PGM_ERR) || read32 (offset) != x) - { - printk (KERN_WARNING "%s: write error at address 0x%.8x.\n",module_name,offset); - return (0); - } - - return (1); -} - -static int flash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf) -{ - __u8 tmp[4]; - int i,n; - -#ifdef LART_DEBUG - printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n", __func__, (__u32)to, len); -#endif - - /* sanity checks */ - if (!len) return (0); - - /* first, we write a 0xFF.... padded byte until we reach a dword boundary */ - if (to & (BUSWIDTH - 1)) - { - __u32 aligned = to & ~(BUSWIDTH - 1); - int gap = to - aligned; - - i = n = 0; - - while (gap--) tmp[i++] = 0xFF; - while (len && i < BUSWIDTH) { - tmp[i++] = buf[n++]; - len--; - } - while (i < BUSWIDTH) tmp[i++] = 0xFF; - - if (!write_dword (aligned,*((__u32 *) tmp))) return (-EIO); - - to += n; - buf += n; - *retlen += n; - } - - /* now we write dwords until we reach a non-dword boundary */ - while (len >= BUSWIDTH) - { - if (!write_dword (to,*((__u32 *) buf))) return (-EIO); - - to += BUSWIDTH; - buf += BUSWIDTH; - *retlen += BUSWIDTH; - len -= BUSWIDTH; - } - - /* top up the last unaligned bytes, padded with 0xFF.... */ - if (len & (BUSWIDTH - 1)) - { - i = n = 0; - - while (len--) tmp[i++] = buf[n++]; - while (i < BUSWIDTH) tmp[i++] = 0xFF; - - if (!write_dword (to,*((__u32 *) tmp))) return (-EIO); - - *retlen += n; - } - - return (0); -} - -/***************************************************************************************************/ - -static struct mtd_info mtd; - -static struct mtd_erase_region_info erase_regions[] = { - /* parameter blocks */ - { - .offset = 0x00000000, - .erasesize = FLASH_BLOCKSIZE_PARAM, - .numblocks = FLASH_NUMBLOCKS_16m_PARAM, - }, - /* main blocks */ - { - .offset = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM, - .erasesize = FLASH_BLOCKSIZE_MAIN, - .numblocks = FLASH_NUMBLOCKS_16m_MAIN, - } -}; - -static const struct mtd_partition lart_partitions[] = { - /* blob */ - { - .name = "blob", - .offset = PART_BLOB_START, - .size = PART_BLOB_LEN, - }, - /* kernel */ - { - .name = "kernel", - .offset = PART_KERNEL_START, /* MTDPART_OFS_APPEND */ - .size = PART_KERNEL_LEN, - }, - /* initial ramdisk / file system */ - { - .name = "file system", - .offset = PART_INITRD_START, /* MTDPART_OFS_APPEND */ - .size = PART_INITRD_LEN, /* MTDPART_SIZ_FULL */ - } -}; -#define NUM_PARTITIONS ARRAY_SIZE(lart_partitions) - -static int __init lart_flash_init (void) -{ - int result; - memset (&mtd,0,sizeof (mtd)); - printk ("MTD driver for LART. Written by Abraham vd Merwe <abraham@2d3d.co.za>\n"); - printk ("%s: Probing for 28F160x3 flash on LART...\n",module_name); - if (!flash_probe ()) - { - printk (KERN_WARNING "%s: Found no LART compatible flash device\n",module_name); - return (-ENXIO); - } - printk ("%s: This looks like a LART board to me.\n",module_name); - mtd.name = module_name; - mtd.type = MTD_NORFLASH; - mtd.writesize = 1; - mtd.writebufsize = 4; - mtd.flags = MTD_CAP_NORFLASH; - mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN; - mtd.erasesize = FLASH_BLOCKSIZE_MAIN; - mtd.numeraseregions = ARRAY_SIZE(erase_regions); - mtd.eraseregions = erase_regions; - mtd._erase = flash_erase; - mtd._read = flash_read; - mtd._write = flash_write; - mtd.owner = THIS_MODULE; - -#ifdef LART_DEBUG - printk (KERN_DEBUG - "mtd.name = %s\n" - "mtd.size = 0x%.8x (%uM)\n" - "mtd.erasesize = 0x%.8x (%uK)\n" - "mtd.numeraseregions = %d\n", - mtd.name, - mtd.size,mtd.size / (1024*1024), - mtd.erasesize,mtd.erasesize / 1024, - mtd.numeraseregions); - - if (mtd.numeraseregions) - for (result = 0; result < mtd.numeraseregions; result++) - printk (KERN_DEBUG - "\n\n" - "mtd.eraseregions[%d].offset = 0x%.8x\n" - "mtd.eraseregions[%d].erasesize = 0x%.8x (%uK)\n" - "mtd.eraseregions[%d].numblocks = %d\n", - result,mtd.eraseregions[result].offset, - result,mtd.eraseregions[result].erasesize,mtd.eraseregions[result].erasesize / 1024, - result,mtd.eraseregions[result].numblocks); - - printk ("\npartitions = %d\n", ARRAY_SIZE(lart_partitions)); - - for (result = 0; result < ARRAY_SIZE(lart_partitions); result++) - printk (KERN_DEBUG - "\n\n" - "lart_partitions[%d].name = %s\n" - "lart_partitions[%d].offset = 0x%.8x\n" - "lart_partitions[%d].size = 0x%.8x (%uK)\n", - result,lart_partitions[result].name, - result,lart_partitions[result].offset, - result,lart_partitions[result].size,lart_partitions[result].size / 1024); -#endif - - result = mtd_device_register(&mtd, lart_partitions, - ARRAY_SIZE(lart_partitions)); - - return (result); -} - -static void __exit lart_flash_exit (void) -{ - mtd_device_unregister(&mtd); -} - -module_init (lart_flash_init); -module_exit (lart_flash_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Abraham vd Merwe <abraham@2d3d.co.za>"); -MODULE_DESCRIPTION("MTD driver for Intel 28F160F3 on LART board"); diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 58ca1c21ebe6..9739387cff8c 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -356,7 +356,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned * Newest unit in chain now contains data from _all_ older units. * So go through and erase each unit in chain, oldest first. (This * is important, by doing oldest first if we crash/reboot then it - * it is relatively simple to clean up the mess). + * is relatively simple to clean up the mess). */ pr_debug("INFTL: want to erase virtual chain %d\n", thisVUC); diff --git a/drivers/mtd/lpddr/lpddr2_nvm.c b/drivers/mtd/lpddr/lpddr2_nvm.c index 367e2d906de0..e71af4c49096 100644 --- a/drivers/mtd/lpddr/lpddr2_nvm.c +++ b/drivers/mtd/lpddr/lpddr2_nvm.c @@ -433,6 +433,8 @@ static int lpddr2_nvm_probe(struct platform_device *pdev) /* lpddr2_nvm address range */ add_range = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!add_range) + return -ENODEV; /* Populate map_info data structure */ *map = (struct map_info) { diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 1749dbbacc13..62a5bf41a6d7 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -64,6 +64,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev) if (!info->map.virt) { printk(KERN_WARNING "Failed to ioremap %s\n", info->map.name); + kfree(info); return -ENOMEM; } info->map.cached = ioremap_cache(info->map.phys, info->map.size); @@ -85,6 +86,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev) iounmap((void *)info->map.virt); if (info->map.cached) iounmap(info->map.cached); + kfree(info); return -EIO; } info->mtd->dev.parent = &pdev->dev; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 0b4ca0aa4132..0feacb9fbdac 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -28,6 +28,7 @@ #include <linux/leds.h> #include <linux/debugfs.h> #include <linux/nvmem-provider.h> +#include <linux/root_dev.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> @@ -551,22 +552,22 @@ static void mtd_check_of_node(struct mtd_info *mtd) struct device_node *partitions, *parent_dn, *mtd_dn = NULL; const char *pname, *prefix = "partition-"; int plen, mtd_name_len, offset, prefix_len; - struct mtd_info *parent; - bool found = false; /* Check if MTD already has a device node */ - if (dev_of_node(&mtd->dev)) + if (mtd_get_of_node(mtd)) return; - /* Check if a partitions node exist */ if (!mtd_is_partition(mtd)) return; - parent = mtd->parent; - parent_dn = of_node_get(dev_of_node(&parent->dev)); + + parent_dn = of_node_get(mtd_get_of_node(mtd->parent)); if (!parent_dn) return; - partitions = of_get_child_by_name(parent_dn, "partitions"); + if (mtd_is_partition(mtd->parent)) + partitions = of_node_get(parent_dn); + else + partitions = of_get_child_by_name(parent_dn, "partitions"); if (!partitions) goto exit_parent; @@ -575,34 +576,26 @@ static void mtd_check_of_node(struct mtd_info *mtd) /* Search if a partition is defined with the same name */ for_each_child_of_node(partitions, mtd_dn) { - offset = 0; - /* Skip partition with no/wrong prefix */ - if (!of_node_name_prefix(mtd_dn, "partition-")) + if (!of_node_name_prefix(mtd_dn, prefix)) continue; /* Label have priority. Check that first */ - if (of_property_read_string(mtd_dn, "label", &pname)) { - of_property_read_string(mtd_dn, "name", &pname); + if (!of_property_read_string(mtd_dn, "label", &pname)) { + offset = 0; + } else { + pname = mtd_dn->name; offset = prefix_len; } plen = strlen(pname) - offset; if (plen == mtd_name_len && !strncmp(mtd->name, pname + offset, plen)) { - found = true; + mtd_set_of_node(mtd, mtd_dn); break; } } - if (!found) - goto exit_partitions; - - /* Set of_node only for nvmem */ - if (of_device_is_compatible(mtd_dn, "nvmem-cells")) - mtd_set_of_node(mtd, mtd_dn); - -exit_partitions: of_node_put(partitions); exit_parent: of_node_put(parent_dn); @@ -723,8 +716,10 @@ int add_mtd_device(struct mtd_info *mtd) mtd_check_of_node(mtd); of_node_get(mtd_get_of_node(mtd)); error = device_register(&mtd->dev); - if (error) + if (error) { + put_device(&mtd->dev); goto fail_added; + } /* Add the nvmem provider */ error = mtd_nvmem_add(mtd); @@ -743,6 +738,17 @@ int add_mtd_device(struct mtd_info *mtd) not->add(mtd); mutex_unlock(&mtd_table_mutex); + + if (of_find_property(mtd_get_of_node(mtd), "linux,rootfs", NULL)) { + if (IS_BUILTIN(CONFIG_MTD)) { + pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name); + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); + } else { + pr_warn("mtd: can't set mtd%d (%s) as root device - mtd must be builtin\n", + mtd->index, mtd->name); + } + } + /* We _know_ we aren't being removed, because our caller is still holding us here. So none of this try_ nonsense, and no bitching about it @@ -774,6 +780,7 @@ int del_mtd_device(struct mtd_info *mtd) { int ret; struct mtd_notifier *not; + struct device_node *mtd_of_node; mutex_lock(&mtd_table_mutex); @@ -792,6 +799,7 @@ int del_mtd_device(struct mtd_info *mtd) mtd->index, mtd->name, mtd->usecount); ret = -EBUSY; } else { + mtd_of_node = mtd_get_of_node(mtd); debugfs_remove_recursive(mtd->dbg.dfs_dir); /* Try to remove the NVMEM provider */ @@ -803,7 +811,7 @@ int del_mtd_device(struct mtd_info *mtd) memset(&mtd->dev, 0, sizeof(mtd->dev)); idr_remove(&mtd_idr, mtd->index); - of_node_put(mtd_get_of_node(mtd)); + of_node_put(mtd_of_node); module_put(THIS_MODULE); ret = 0; @@ -2483,6 +2491,7 @@ static int __init init_mtd(void) out_procfs: if (proc_mtd) remove_proc_entry("mtd", NULL); + bdi_unregister(mtd_bdi); bdi_put(mtd_bdi); err_bdi: class_unregister(&mtd_class); diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 3d4a2ffb5b01..2f11585b5613 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -7,6 +7,8 @@ * Author: Richard Purdie <rpurdie@openedhand.com> */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/console.h> @@ -93,9 +95,9 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset) ret = mtd_erase(mtd, &erase); if (ret) { - printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n", - (unsigned long long)erase.addr, - (unsigned long long)erase.len, mtddev); + pr_warn("erase of region [0x%llx, 0x%llx] on \"%s\" failed\n", + (unsigned long long)erase.addr, + (unsigned long long)erase.len, mtddev); return ret; } @@ -106,29 +108,8 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset) return 0; } -static void mtdoops_inc_counter(struct mtdoops_context *cxt) -{ - cxt->nextpage++; - if (cxt->nextpage >= cxt->oops_pages) - cxt->nextpage = 0; - cxt->nextcount++; - if (cxt->nextcount == 0xffffffff) - cxt->nextcount = 0; - - if (page_is_used(cxt, cxt->nextpage)) { - schedule_work(&cxt->work_erase); - return; - } - - printk(KERN_DEBUG "mtdoops: ready %d, %d (no erase)\n", - cxt->nextpage, cxt->nextcount); -} - -/* Scheduled work - when we can't proceed without erasing a block */ -static void mtdoops_workfunc_erase(struct work_struct *work) +static void mtdoops_erase(struct mtdoops_context *cxt) { - struct mtdoops_context *cxt = - container_of(work, struct mtdoops_context, work_erase); struct mtd_info *mtd = cxt->mtd; int i = 0, j, ret, mod; @@ -145,20 +126,20 @@ static void mtdoops_workfunc_erase(struct work_struct *work) while ((ret = mtd_block_isbad(mtd, cxt->nextpage * record_size)) > 0) { badblock: - printk(KERN_WARNING "mtdoops: bad block at %08lx\n", - cxt->nextpage * record_size); + pr_warn("bad block at %08lx\n", + cxt->nextpage * record_size); i++; cxt->nextpage = cxt->nextpage + (mtd->erasesize / record_size); if (cxt->nextpage >= cxt->oops_pages) cxt->nextpage = 0; if (i == cxt->oops_pages / (mtd->erasesize / record_size)) { - printk(KERN_ERR "mtdoops: all blocks bad!\n"); + pr_err("all blocks bad!\n"); return; } } if (ret < 0) { - printk(KERN_ERR "mtdoops: mtd_block_isbad failed, aborting\n"); + pr_err("mtd_block_isbad failed, aborting\n"); return; } @@ -166,21 +147,55 @@ badblock: ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size); if (ret >= 0) { - printk(KERN_DEBUG "mtdoops: ready %d, %d\n", - cxt->nextpage, cxt->nextcount); + pr_debug("ready %d, %d\n", + cxt->nextpage, cxt->nextcount); return; } if (ret == -EIO) { ret = mtd_block_markbad(mtd, cxt->nextpage * record_size); if (ret < 0 && ret != -EOPNOTSUPP) { - printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n"); + pr_err("block_markbad failed, aborting\n"); return; } } goto badblock; } +/* Scheduled work - when we can't proceed without erasing a block */ +static void mtdoops_workfunc_erase(struct work_struct *work) +{ + struct mtdoops_context *cxt = + container_of(work, struct mtdoops_context, work_erase); + mtdoops_erase(cxt); +} + +static void mtdoops_inc_counter(struct mtdoops_context *cxt, int panic) +{ + cxt->nextpage++; + if (cxt->nextpage >= cxt->oops_pages) + cxt->nextpage = 0; + cxt->nextcount++; + if (cxt->nextcount == 0xffffffff) + cxt->nextcount = 0; + + if (page_is_used(cxt, cxt->nextpage)) { + pr_debug("not ready %d, %d (erase %s)\n", + cxt->nextpage, cxt->nextcount, + panic ? "immediately" : "scheduled"); + if (panic) { + /* In case of panic, erase immediately */ + mtdoops_erase(cxt); + } else { + /* Otherwise, schedule work to erase it "nicely" */ + schedule_work(&cxt->work_erase); + } + } else { + pr_debug("ready %d, %d (no erase)\n", + cxt->nextpage, cxt->nextcount); + } +} + static void mtdoops_write(struct mtdoops_context *cxt, int panic) { struct mtd_info *mtd = cxt->mtd; @@ -201,7 +216,7 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic) ret = mtd_panic_write(mtd, cxt->nextpage * record_size, record_size, &retlen, cxt->oops_buf); if (ret == -EOPNOTSUPP) { - printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n"); + pr_err("Cannot write from panic without panic_write\n"); goto out; } } else @@ -209,12 +224,12 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic) record_size, &retlen, cxt->oops_buf); if (retlen != record_size || ret < 0) - printk(KERN_ERR "mtdoops: write failure at %ld (%td of %ld written), error %d\n", + pr_err("write failure at %ld (%td of %ld written), error %d\n", cxt->nextpage * record_size, retlen, record_size, ret); mark_page_used(cxt, cxt->nextpage); memset(cxt->oops_buf, 0xff, record_size); - mtdoops_inc_counter(cxt); + mtdoops_inc_counter(cxt, panic); out: clear_bit(0, &cxt->oops_buf_busy); } @@ -244,7 +259,7 @@ static void find_next_position(struct mtdoops_context *cxt) &retlen, (u_char *)&hdr); if (retlen != sizeof(hdr) || (ret < 0 && !mtd_is_bitflip(ret))) { - printk(KERN_ERR "mtdoops: read failure at %ld (%zu of %zu read), err %d\n", + pr_err("read failure at %ld (%zu of %zu read), err %d\n", page * record_size, retlen, sizeof(hdr), ret); continue; } @@ -279,7 +294,7 @@ static void find_next_position(struct mtdoops_context *cxt) cxt->nextcount = maxcount; } - mtdoops_inc_counter(cxt); + mtdoops_inc_counter(cxt, 0); } static void mtdoops_do_dump(struct kmsg_dumper *dumper, @@ -324,17 +339,17 @@ static void mtdoops_notify_add(struct mtd_info *mtd) return; if (mtd->size < mtd->erasesize * 2) { - printk(KERN_ERR "mtdoops: MTD partition %d not big enough for mtdoops\n", + pr_err("MTD partition %d not big enough for mtdoops\n", mtd->index); return; } if (mtd->erasesize < record_size) { - printk(KERN_ERR "mtdoops: eraseblock size of MTD partition %d too small\n", + pr_err("eraseblock size of MTD partition %d too small\n", mtd->index); return; } if (mtd->size > MTDOOPS_MAX_MTD_SIZE) { - printk(KERN_ERR "mtdoops: mtd%d is too large (limit is %d MiB)\n", + pr_err("mtd%d is too large (limit is %d MiB)\n", mtd->index, MTDOOPS_MAX_MTD_SIZE / 1024 / 1024); return; } @@ -345,7 +360,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) DIV_ROUND_UP(mtdoops_pages, BITS_PER_LONG))); if (!cxt->oops_page_used) { - printk(KERN_ERR "mtdoops: could not allocate page array\n"); + pr_err("could not allocate page array\n"); return; } @@ -353,7 +368,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) cxt->dump.dump = mtdoops_do_dump; err = kmsg_dump_register(&cxt->dump); if (err) { - printk(KERN_ERR "mtdoops: registering kmsg dumper failed, error %d\n", err); + pr_err("registering kmsg dumper failed, error %d\n", err); vfree(cxt->oops_page_used); cxt->oops_page_used = NULL; return; @@ -362,7 +377,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) cxt->mtd = mtd; cxt->oops_pages = (int)mtd->size / record_size; find_next_position(cxt); - printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index); + pr_info("Attached to MTD device %d\n", mtd->index); } static void mtdoops_notify_remove(struct mtd_info *mtd) @@ -373,7 +388,7 @@ static void mtdoops_notify_remove(struct mtd_info *mtd) return; if (kmsg_dump_unregister(&cxt->dump) < 0) - printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n"); + pr_warn("could not unregister kmsg_dumper\n"); cxt->mtd = NULL; flush_work(&cxt->work_erase); @@ -393,15 +408,15 @@ static int __init mtdoops_init(void) char *endp; if (strlen(mtddev) == 0) { - printk(KERN_ERR "mtdoops: mtd device (mtddev=name/number) must be supplied\n"); + pr_err("mtd device (mtddev=name/number) must be supplied\n"); return -EINVAL; } if ((record_size & 4095) != 0) { - printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n"); + pr_err("record_size must be a multiple of 4096\n"); return -EINVAL; } if (record_size < 4096) { - printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n"); + pr_err("record_size must be over 4096 bytes\n"); return -EINVAL; } diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c index dbd7b06524b3..7737b1a4a177 100644 --- a/drivers/mtd/nand/core.c +++ b/drivers/mtd/nand/core.c @@ -126,7 +126,7 @@ EXPORT_SYMBOL_GPL(nanddev_isreserved); * * Return: 0 in case of success, a negative error code otherwise. */ -int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos) +static int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos) { if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) { pr_warn("attempt to erase a bad/reserved block @%llx\n", @@ -136,7 +136,6 @@ int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos) return nand->ops->erase(nand, pos); } -EXPORT_SYMBOL_GPL(nanddev_erase); /** * nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 4cd40af362de..98ea1c9e65c8 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -415,7 +415,7 @@ config MTD_NAND_PLATFORM config MTD_NAND_CADENCE tristate "Support Cadence NAND (HPNFC) controller" - depends on (OF || COMPILE_TEST) && HAS_IOMEM + depends on OF && HAS_IOMEM help Enable the driver for NAND flash on platforms using a Cadence NAND controller. @@ -430,7 +430,7 @@ config MTD_NAND_ARASAN config MTD_NAND_INTEL_LGM tristate "Support for NAND controller on Intel LGM SoC" - depends on OF || COMPILE_TEST + depends on OF depends on HAS_IOMEM help Enables support for NAND Flash chips on Intel's LGM SoC. @@ -450,7 +450,7 @@ config MTD_NAND_ROCKCHIP config MTD_NAND_PL35X tristate "ARM PL35X NAND controller" - depends on OF || COMPILE_TEST + depends on OF depends on PL353_SMC help Enables support for PrimeCell SMC PL351 and PL353 NAND diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c index 9dac3ca69d57..7661a5cf1883 100644 --- a/drivers/mtd/nand/raw/cadence-nand-controller.c +++ b/drivers/mtd/nand/raw/cadence-nand-controller.c @@ -1184,6 +1184,14 @@ static int cadence_nand_hw_init(struct cdns_nand_ctrl *cdns_ctrl) if (cadence_nand_read_bch_caps(cdns_ctrl)) return -EIO; +#ifndef CONFIG_64BIT + if (cdns_ctrl->caps2.data_dma_width == 8) { + dev_err(cdns_ctrl->dev, + "cannot access 64-bit dma on !64-bit architectures"); + return -EIO; + } +#endif + /* * Set IO width access to 8. * It is because during SW device discovering width access @@ -1882,17 +1890,36 @@ static int cadence_nand_read_buf(struct cdns_nand_ctrl *cdns_ctrl, return status; if (!cdns_ctrl->caps1->has_dma) { - int len_in_words = len >> 2; + u8 data_dma_width = cdns_ctrl->caps2.data_dma_width; + + int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3; /* read alingment data */ - ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words); + if (data_dma_width == 4) + ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words); +#ifdef CONFIG_64BIT + else + readsq(cdns_ctrl->io.virt, buf, len_in_words); +#endif + if (sdma_size > len) { + int read_bytes = (data_dma_width == 4) ? + len_in_words << 2 : len_in_words << 3; + /* read rest data from slave DMA interface if any */ - ioread32_rep(cdns_ctrl->io.virt, cdns_ctrl->buf, - sdma_size / 4 - len_in_words); + if (data_dma_width == 4) + ioread32_rep(cdns_ctrl->io.virt, + cdns_ctrl->buf, + sdma_size / 4 - len_in_words); +#ifdef CONFIG_64BIT + else + readsq(cdns_ctrl->io.virt, cdns_ctrl->buf, + sdma_size / 8 - len_in_words); +#endif + /* copy rest of data */ - memcpy(buf + (len_in_words << 2), cdns_ctrl->buf, - len - (len_in_words << 2)); + memcpy(buf + read_bytes, cdns_ctrl->buf, + len - read_bytes); } return 0; } @@ -1936,16 +1963,35 @@ static int cadence_nand_write_buf(struct cdns_nand_ctrl *cdns_ctrl, return status; if (!cdns_ctrl->caps1->has_dma) { - int len_in_words = len >> 2; + u8 data_dma_width = cdns_ctrl->caps2.data_dma_width; + + int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3; + + if (data_dma_width == 4) + iowrite32_rep(cdns_ctrl->io.virt, buf, len_in_words); +#ifdef CONFIG_64BIT + else + writesq(cdns_ctrl->io.virt, buf, len_in_words); +#endif - iowrite32_rep(cdns_ctrl->io.virt, buf, len_in_words); if (sdma_size > len) { + int written_bytes = (data_dma_width == 4) ? + len_in_words << 2 : len_in_words << 3; + /* copy rest of data */ - memcpy(cdns_ctrl->buf, buf + (len_in_words << 2), - len - (len_in_words << 2)); + memcpy(cdns_ctrl->buf, buf + written_bytes, + len - written_bytes); + /* write all expected by nand controller data */ - iowrite32_rep(cdns_ctrl->io.virt, cdns_ctrl->buf, - sdma_size / 4 - len_in_words); + if (data_dma_width == 4) + iowrite32_rep(cdns_ctrl->io.virt, + cdns_ctrl->buf, + sdma_size / 4 - len_in_words); +#ifdef CONFIG_64BIT + else + writesq(cdns_ctrl->io.virt, cdns_ctrl->buf, + sdma_size / 8 - len_in_words); +#endif } return 0; diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 01ccbde748f3..ada83344b0f9 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -148,11 +148,9 @@ static int gpmi_init(struct gpmi_nand_data *this) struct resources *r = &this->resources; int ret; - ret = pm_runtime_get_sync(this->dev); - if (ret < 0) { - pm_runtime_put_noidle(this->dev); + ret = pm_runtime_resume_and_get(this->dev); + if (ret < 0) return ret; - } ret = gpmi_reset_block(r->gpmi_regs, false); if (ret) @@ -2504,11 +2502,9 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip, for (i = 0; i < GPMI_MAX_TRANSFERS; i++) this->transfers[i].direction = DMA_NONE; - ret = pm_runtime_get_sync(this->dev); - if (ret < 0) { - pm_runtime_put_noidle(this->dev); + ret = pm_runtime_resume_and_get(this->dev); + if (ret < 0) return ret; - } /* * This driver currently supports only one NAND chip. Plus, dies share diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c index 452ecaf7775a..ae7f6429a5f6 100644 --- a/drivers/mtd/nand/raw/lpc32xx_mlc.c +++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c @@ -25,7 +25,7 @@ #include <linux/completion.h> #include <linux/interrupt.h> #include <linux/of.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/mtd/lpc32xx_mlc.h> #include <linux/io.h> #include <linux/mm.h> @@ -122,7 +122,6 @@ struct lpc32xx_nand_cfg_mlc { uint32_t rd_low; uint32_t wr_high; uint32_t wr_low; - int wp_gpio; struct mtd_partition *parts; unsigned num_parts; }; @@ -177,6 +176,7 @@ struct lpc32xx_nand_host { struct nand_chip nand_chip; struct lpc32xx_mlc_platform_data *pdata; struct clk *clk; + struct gpio_desc *wp_gpio; void __iomem *io_base; int irq; struct lpc32xx_nand_cfg_mlc *ncfg; @@ -370,8 +370,8 @@ static int lpc32xx_waitfunc(struct nand_chip *chip) */ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) { - if (gpio_is_valid(host->ncfg->wp_gpio)) - gpio_set_value(host->ncfg->wp_gpio, 0); + if (host->wp_gpio) + gpiod_set_value_cansleep(host->wp_gpio, 1); } /* @@ -379,8 +379,8 @@ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) */ static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) { - if (gpio_is_valid(host->ncfg->wp_gpio)) - gpio_set_value(host->ncfg->wp_gpio, 1); + if (host->wp_gpio) + gpiod_set_value_cansleep(host->wp_gpio, 0); } static void lpc32xx_dma_complete_func(void *completion) @@ -636,8 +636,6 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev) return NULL; } - ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0); - return ncfg; } @@ -713,14 +711,18 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) "Missing or bad NAND config from device tree\n"); return -ENOENT; } - if (host->ncfg->wp_gpio == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (gpio_is_valid(host->ncfg->wp_gpio) && - gpio_request(host->ncfg->wp_gpio, "NAND WP")) { - dev_err(&pdev->dev, "GPIO not available\n"); - return -EBUSY; + + /* Start with WP disabled, if available */ + host->wp_gpio = gpiod_get_optional(&pdev->dev, NULL, GPIOD_OUT_LOW); + res = PTR_ERR_OR_ZERO(host->wp_gpio); + if (res) { + if (res != -EPROBE_DEFER) + dev_err(&pdev->dev, "WP GPIO is not available: %d\n", + res); + return res; } - lpc32xx_wp_disable(host); + + gpiod_set_consumer_name(host->wp_gpio, "NAND WP"); host->pdata = dev_get_platdata(&pdev->dev); @@ -817,7 +819,7 @@ put_clk: clk_put(host->clk); free_gpio: lpc32xx_wp_enable(host); - gpio_free(host->ncfg->wp_gpio); + gpiod_put(host->wp_gpio); return res; } @@ -843,12 +845,11 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) clk_put(host->clk); lpc32xx_wp_enable(host); - gpio_free(host->ncfg->wp_gpio); + gpiod_put(host->wp_gpio); return 0; } -#ifdef CONFIG_PM static int lpc32xx_nand_resume(struct platform_device *pdev) { struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); @@ -880,11 +881,6 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) return 0; } -#else -#define lpc32xx_nand_resume NULL -#define lpc32xx_nand_suspend NULL -#endif - static const struct of_device_id lpc32xx_nand_match[] = { { .compatible = "nxp,lpc3220-mlc" }, { /* sentinel */ }, @@ -894,8 +890,8 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); static struct platform_driver lpc32xx_nand_driver = { .probe = lpc32xx_nand_probe, .remove = lpc32xx_nand_remove, - .resume = lpc32xx_nand_resume, - .suspend = lpc32xx_nand_suspend, + .resume = pm_ptr(lpc32xx_nand_resume), + .suspend = pm_ptr(lpc32xx_nand_suspend), .driver = { .name = DRV_NAME, .of_match_table = lpc32xx_nand_match, diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c index 6b7269cfb7d8..6918737346c9 100644 --- a/drivers/mtd/nand/raw/lpc32xx_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c @@ -23,9 +23,8 @@ #include <linux/mm.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/mtd/lpc32xx_slc.h> #define LPC32XX_MODNAME "lpc32xx-nand" @@ -208,7 +207,6 @@ struct lpc32xx_nand_cfg_slc { uint32_t rwidth; uint32_t rhold; uint32_t rsetup; - int wp_gpio; struct mtd_partition *parts; unsigned num_parts; }; @@ -217,6 +215,7 @@ struct lpc32xx_nand_host { struct nand_chip nand_chip; struct lpc32xx_slc_platform_data *pdata; struct clk *clk; + struct gpio_desc *wp_gpio; void __iomem *io_base; struct lpc32xx_nand_cfg_slc *ncfg; @@ -309,8 +308,8 @@ static int lpc32xx_nand_device_ready(struct nand_chip *chip) */ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) { - if (gpio_is_valid(host->ncfg->wp_gpio)) - gpio_set_value(host->ncfg->wp_gpio, 0); + if (host->wp_gpio) + gpiod_set_value_cansleep(host->wp_gpio, 1); } /* @@ -318,8 +317,8 @@ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) */ static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) { - if (gpio_is_valid(host->ncfg->wp_gpio)) - gpio_set_value(host->ncfg->wp_gpio, 1); + if (host->wp_gpio) + gpiod_set_value_cansleep(host->wp_gpio, 0); } /* @@ -764,8 +763,6 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) return NULL; } - ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0); - return ncfg; } @@ -852,14 +849,18 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) "Missing or bad NAND config from device tree\n"); return -ENOENT; } - if (host->ncfg->wp_gpio == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev, - host->ncfg->wp_gpio, "NAND WP")) { - dev_err(&pdev->dev, "GPIO not available\n"); - return -EBUSY; + + /* Start with WP disabled, if available */ + host->wp_gpio = gpiod_get_optional(&pdev->dev, NULL, GPIOD_OUT_LOW); + res = PTR_ERR_OR_ZERO(host->wp_gpio); + if (res) { + if (res != -EPROBE_DEFER) + dev_err(&pdev->dev, "WP GPIO is not available: %d\n", + res); + return res; } - lpc32xx_wp_disable(host); + + gpiod_set_consumer_name(host->wp_gpio, "NAND WP"); host->pdata = dev_get_platdata(&pdev->dev); @@ -968,7 +969,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM static int lpc32xx_nand_resume(struct platform_device *pdev) { struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); @@ -1007,11 +1007,6 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) return 0; } -#else -#define lpc32xx_nand_resume NULL -#define lpc32xx_nand_suspend NULL -#endif - static const struct of_device_id lpc32xx_nand_match[] = { { .compatible = "nxp,lpc3220-slc" }, { /* sentinel */ }, @@ -1021,8 +1016,8 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); static struct platform_driver lpc32xx_nand_driver = { .probe = lpc32xx_nand_probe, .remove = lpc32xx_nand_remove, - .resume = lpc32xx_nand_resume, - .suspend = lpc32xx_nand_suspend, + .resume = pm_ptr(lpc32xx_nand_resume), + .suspend = pm_ptr(lpc32xx_nand_suspend), .driver = { .name = LPC32XX_MODNAME, .of_match_table = lpc32xx_nand_match, diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index b9d1e96e3334..42c64dcea767 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -114,6 +114,7 @@ #define GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST BIT(20) #define GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST BIT(21) #define GENCONF_SOC_DEVICE_MUX_NFC_INT_EN BIT(25) +#define GENCONF_SOC_DEVICE_MUX_NFC_DEVBUS_ARB_EN BIT(27) #define GENCONF_CLK_GATING_CTRL 0x220 #define GENCONF_CLK_GATING_CTRL_ND_GATE BIT(2) #define GENCONF_ND_CLK_CTRL 0x700 @@ -2880,7 +2881,8 @@ static int marvell_nfc_init(struct marvell_nfc *nfc) GENCONF_SOC_DEVICE_MUX_NFC_EN | GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST | GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST | - GENCONF_SOC_DEVICE_MUX_NFC_INT_EN); + GENCONF_SOC_DEVICE_MUX_NFC_INT_EN | + GENCONF_SOC_DEVICE_MUX_NFC_DEVBUS_ARB_EN); regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL, GENCONF_CLK_GATING_CTRL_ND_GATE, diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c index 800d774aed8e..f68349cb7824 100644 --- a/drivers/mtd/nand/raw/mpc5121_nfc.c +++ b/drivers/mtd/nand/raw/mpc5121_nfc.c @@ -663,7 +663,7 @@ static int mpc5121_nfc_probe(struct platform_device *op) } prv->irq = irq_of_parse_and_map(dn, 0); - if (prv->irq == NO_IRQ) { + if (!prv->irq) { dev_err(dev, "Error mapping IRQ!\n"); return -EINVAL; } diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index 76684428354e..3ad58cd284d8 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -74,9 +74,75 @@ static int w25m02gv_select_target(struct spinand_device *spinand, return spi_mem_exec_op(spinand->spimem, &op); } +static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + region->offset = 64 + (16 * section); + region->length = 13; + + return 0; +} + +static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + region->offset = (16 * section) + 2; + region->length = 14; + + return 0; +} + +static const struct mtd_ooblayout_ops w25n02kv_ooblayout = { + .ecc = w25n02kv_ooblayout_ecc, + .free = w25n02kv_ooblayout_free, +}; + +static int w25n02kv_ecc_get_status(struct spinand_device *spinand, + u8 status) +{ + struct nand_device *nand = spinand_to_nand(spinand); + u8 mbf = 0; + struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf); + + switch (status & STATUS_ECC_MASK) { + case STATUS_ECC_NO_BITFLIPS: + return 0; + + case STATUS_ECC_UNCOR_ERROR: + return -EBADMSG; + + case STATUS_ECC_HAS_BITFLIPS: + /* + * Let's try to retrieve the real maximum number of bitflips + * in order to avoid forcing the wear-leveling layer to move + * data around if it's not necessary. + */ + if (spi_mem_exec_op(spinand->spimem, &op)) + return nanddev_get_ecc_conf(nand)->strength; + + mbf >>= 4; + + if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf)) + return nanddev_get_ecc_conf(nand)->strength; + + return mbf; + + default: + break; + } + + return -EINVAL; +} + static const struct spinand_info winbond_spinand_table[] = { SPINAND_INFO("W25M02GV", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2), NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -86,7 +152,7 @@ static const struct spinand_info winbond_spinand_table[] = { SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), SPINAND_SELECT_TARGET(w25m02gv_select_target)), SPINAND_INFO("W25N01GV", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -94,6 +160,15 @@ static const struct spinand_info winbond_spinand_table[] = { &update_cache_variants), 0, SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), + SPINAND_INFO("W25N02KV", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), + 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), + 0, + SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), }; static int winbond_spinand_init(struct spinand_device *spinand) diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig index aaa06050c9bc..b20e0c38b517 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig @@ -22,7 +22,7 @@ config MTD_BCM63XX_PARTS config MTD_BRCM_U_BOOT tristate "Broadcom's U-Boot partition parser" - depends on ARCH_BCM4908 || COMPILE_TEST + depends on ARCH_BCMBCA || COMPILE_TEST help Broadcom uses a custom way of storing U-Boot environment variables. They are placed inside U-Boot partition itself at unspecified offset. @@ -75,7 +75,7 @@ config MTD_OF_PARTS This provides a open firmware device tree partition parser which derives the partition map from the children of the flash memory node, as described in - Documentation/devicetree/bindings/mtd/partition.txt. + Documentation/devicetree/bindings/mtd/mtd.yaml. config MTD_OF_PARTS_BCM4908 bool "BCM4908 partitioning support" @@ -123,6 +123,21 @@ config MTD_AFS_PARTS for your particular device. It won't happen automatically. The 'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example. +config MTD_PARSER_TPLINK_SAFELOADER + tristate "TP-Link Safeloader partitions parser" + depends on MTD && (ARCH_BCM_5301X || ATH79 || SOC_MT7620 || SOC_MT7621 || COMPILE_TEST) + help + TP-Link home routers use flash partitions to store various data. Info + about flash space layout is stored in a partitions table using a + custom ASCII-based format. + + That format was first found in devices with SafeLoader bootloader and + was named after it. Later it was adapted to CFE and U-Boot + bootloaders. + + This driver reads partitions table, parses it and creates MTD + partitions. + config MTD_PARSER_TRX tristate "Parser for TRX format partitions" depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || RALINK || COMPILE_TEST) diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile index 23fa4de4016f..0e70b621a1d8 100644 --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile @@ -10,6 +10,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o +obj-$(CONFIG_MTD_PARSER_TPLINK_SAFELOADER) += tplink_safeloader.o obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o diff --git a/drivers/mtd/parsers/tplink_safeloader.c b/drivers/mtd/parsers/tplink_safeloader.c new file mode 100644 index 000000000000..f601e7bd8627 --- /dev/null +++ b/drivers/mtd/parsers/tplink_safeloader.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright © 2022 Rafał Miłecki <rafal@milecki.pl> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/of.h> +#include <linux/slab.h> + +#define TPLINK_SAFELOADER_DATA_OFFSET 4 +#define TPLINK_SAFELOADER_MAX_PARTS 32 + +struct safeloader_cmn_header { + __be32 size; + uint32_t unused; +} __packed; + +static void *mtd_parser_tplink_safeloader_read_table(struct mtd_info *mtd) +{ + struct safeloader_cmn_header hdr; + struct device_node *np; + size_t bytes_read; + size_t size; + u32 offset; + char *buf; + int err; + + np = mtd_get_of_node(mtd); + if (mtd_is_partition(mtd)) + of_node_get(np); + else + np = of_get_child_by_name(np, "partitions"); + + if (of_property_read_u32(np, "partitions-table-offset", &offset)) { + pr_err("Failed to get partitions table offset\n"); + goto err_put; + } + + err = mtd_read(mtd, offset, sizeof(hdr), &bytes_read, (uint8_t *)&hdr); + if (err && !mtd_is_bitflip(err)) { + pr_err("Failed to read from %s at 0x%x\n", mtd->name, offset); + goto err_put; + } + + size = be32_to_cpu(hdr.size); + + buf = kmalloc(size + 1, GFP_KERNEL); + if (!buf) + goto err_put; + + err = mtd_read(mtd, offset + sizeof(hdr), size, &bytes_read, buf); + if (err && !mtd_is_bitflip(err)) { + pr_err("Failed to read from %s at 0x%zx\n", mtd->name, offset + sizeof(hdr)); + goto err_kfree; + } + + buf[size] = '\0'; + + of_node_put(np); + + return buf; + +err_kfree: + kfree(buf); +err_put: + of_node_put(np); + return NULL; +} + +static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + char name[65]; + size_t offset; + size_t bytes; + char *buf; + int idx; + int err; + + parts = kcalloc(TPLINK_SAFELOADER_MAX_PARTS, sizeof(*parts), GFP_KERNEL); + if (!parts) { + err = -ENOMEM; + goto err_out; + } + + buf = mtd_parser_tplink_safeloader_read_table(mtd); + if (!buf) { + err = -ENOENT; + goto err_out; + } + + for (idx = 0, offset = TPLINK_SAFELOADER_DATA_OFFSET; + idx < TPLINK_SAFELOADER_MAX_PARTS && + sscanf(buf + offset, "partition %64s base 0x%llx size 0x%llx%zn\n", + name, &parts[idx].offset, &parts[idx].size, &bytes) == 3; + idx++, offset += bytes + 1) { + parts[idx].name = kstrdup(name, GFP_KERNEL); + if (!parts[idx].name) { + err = -ENOMEM; + goto err_free; + } + } + + if (idx == TPLINK_SAFELOADER_MAX_PARTS) + pr_warn("Reached maximum number of partitions!\n"); + + kfree(buf); + + *pparts = parts; + + return idx; + +err_free: + for (idx -= 1; idx >= 0; idx--) + kfree(parts[idx].name); +err_out: + return err; +}; + +static void mtd_parser_tplink_safeloader_cleanup(const struct mtd_partition *pparts, + int nr_parts) +{ + int i; + + for (i = 0; i < nr_parts; i++) + kfree(pparts[i].name); + + kfree(pparts); +} + +static const struct of_device_id mtd_parser_tplink_safeloader_of_match_table[] = { + { .compatible = "tplink,safeloader-partitions" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtd_parser_tplink_safeloader_of_match_table); + +static struct mtd_part_parser mtd_parser_tplink_safeloader = { + .parse_fn = mtd_parser_tplink_safeloader_parse, + .cleanup = mtd_parser_tplink_safeloader_cleanup, + .name = "tplink-safeloader", + .of_match_table = mtd_parser_tplink_safeloader_of_match_table, +}; +module_mtd_part_parser(mtd_parser_tplink_safeloader); + +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index bee8fc4c9f07..d8703d7dfd0a 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1184,6 +1184,8 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map, continue; erase = &map->erase_type[i]; + if (!erase->size) + continue; /* Alignment is not mandatory for overlaid regions */ if (region->offset & SNOR_OVERLAID_REGION && @@ -1632,6 +1634,16 @@ static const struct spi_nor_manufacturer *manufacturers[] = { &spi_nor_xmc, }; +static const struct flash_info spi_nor_generic_flash = { + .name = "spi-nor-generic", + /* + * JESD216 rev A doesn't specify the page size, therefore we need a + * sane default. + */ + .page_size = 256, + .parse_sfdp = true, +}; + static const struct flash_info *spi_nor_match_id(struct spi_nor *nor, const u8 *id) { @@ -1664,7 +1676,20 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor) return ERR_PTR(ret); } + /* Cache the complete flash ID. */ + nor->id = devm_kmemdup(nor->dev, id, SPI_NOR_MAX_ID_LEN, GFP_KERNEL); + if (!nor->id) + return ERR_PTR(-ENOMEM); + info = spi_nor_match_id(nor, id); + + /* Fallback to a generic flash described only by its SFDP data. */ + if (!info) { + ret = spi_nor_check_sfdp_signature(nor); + if (!ret) + info = &spi_nor_generic_flash; + } + if (!info) { dev_err(nor->dev, "unrecognized JEDEC id bytes: %*ph\n", SPI_NOR_MAX_ID_LEN, id); @@ -1914,7 +1939,8 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor, spi_nor_spimem_setup_op(nor, &op, read->proto); /* convert the dummy cycles to the number of bytes */ - op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8; + op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) * + op.dummy.buswidth / 8; if (spi_nor_protocol_is_dtr(nor->read_proto)) op.dummy.nbytes *= 2; @@ -2091,8 +2117,12 @@ static int spi_nor_select_pp(struct spi_nor *nor, * spi_nor_select_uniform_erase() - select optimum uniform erase type * @map: the erase map of the SPI NOR * @wanted_size: the erase type size to search for. Contains the value of - * info->sector_size or of the "small sector" size in case - * CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined. + * info->sector_size, the "small sector" size in case + * CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined or 0 if + * there is no information about the sector size. The + * latter is the case if the flash parameters are parsed + * solely by SFDP, then the largest supported erase type + * is selected. * * Once the optimum uniform sector erase command is found, disable all the * other. @@ -2113,6 +2143,10 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map, tested_erase = &map->erase_type[i]; + /* Skip masked erase types. */ + if (!tested_erase->size) + continue; + /* * If the current erase size is the one, stop here: * we have found the right uniform Sector Erase command. @@ -2565,6 +2599,12 @@ static void spi_nor_init_default_params(struct spi_nor *nor) params->hwcaps.mask |= SNOR_HWCAPS_PP; spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], SPINOR_OP_PP, SNOR_PROTO_1_1_1); + + if (info->flags & SPI_NOR_QUAD_PP) { + params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4; + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4], + SPINOR_OP_PP_1_1_4, SNOR_PROTO_1_1_4); + } } /** @@ -2840,10 +2880,20 @@ static void spi_nor_put_device(struct mtd_info *mtd) void spi_nor_restore(struct spi_nor *nor) { + int ret; + /* restore the addressing mode */ if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) && - nor->flags & SNOR_F_BROKEN_RESET) - nor->params->set_4byte_addr_mode(nor, false); + nor->flags & SNOR_F_BROKEN_RESET) { + ret = nor->params->set_4byte_addr_mode(nor, false); + if (ret) + /* + * Do not stop the execution in the hope that the flash + * will default to the 3-byte address mode after the + * software reset. + */ + dev_err(nor->dev, "Failed to exit 4-byte address mode, err = %d\n", ret); + } if (nor->flags & SNOR_F_SOFT_RESET) spi_nor_soft_reset(nor); @@ -2935,6 +2985,27 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor) mtd->_put_device = spi_nor_put_device; } +static int spi_nor_hw_reset(struct spi_nor *nor) +{ + struct gpio_desc *reset; + + reset = devm_gpiod_get_optional(nor->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR_OR_NULL(reset)) + return PTR_ERR_OR_ZERO(reset); + + /* + * Experimental delay values by looking at different flash device + * vendors datasheets. + */ + usleep_range(1, 5); + gpiod_set_value_cansleep(reset, 1); + usleep_range(100, 150); + gpiod_set_value_cansleep(reset, 0); + usleep_range(1000, 1200); + + return 0; +} + int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps) { @@ -2967,6 +3038,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (!nor->bouncebuf) return -ENOMEM; + ret = spi_nor_hw_reset(nor); + if (ret) + return ret; + info = spi_nor_get_flash_info(nor, name); if (IS_ERR(info)) return PTR_ERR(info); diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 85b0cf254e97..f03b55cf7e6f 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -458,6 +458,7 @@ struct spi_nor_fixups { * SPI_NOR_NO_ERASE: no erase command needed. * NO_CHIP_ERASE: chip does not support chip erase. * SPI_NOR_NO_FR: can't do fastread. + * SPI_NOR_QUAD_PP: flash supports Quad Input Page Program. * * @no_sfdp_flags: flags that indicate support that can be discovered via SFDP. * Used when SFDP tables are not defined in the flash. These @@ -507,6 +508,7 @@ struct flash_info { #define SPI_NOR_NO_ERASE BIT(6) #define NO_CHIP_ERASE BIT(7) #define SPI_NOR_NO_FR BIT(8) +#define SPI_NOR_QUAD_PP BIT(9) u8 no_sfdp_flags; #define SPI_NOR_SKIP_SFDP BIT(0) @@ -701,6 +703,9 @@ int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode, int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf, size_t len); +int spi_nor_check_sfdp_signature(struct spi_nor *nor); +int spi_nor_parse_sfdp(struct spi_nor *nor); + static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) { return container_of(mtd, struct spi_nor, mtd); diff --git a/drivers/mtd/spi-nor/debugfs.c b/drivers/mtd/spi-nor/debugfs.c index df76cb5de3f9..ff895f6758ea 100644 --- a/drivers/mtd/spi-nor/debugfs.c +++ b/drivers/mtd/spi-nor/debugfs.c @@ -81,7 +81,7 @@ static int spi_nor_params_show(struct seq_file *s, void *data) int i; seq_printf(s, "name\t\t%s\n", info->name); - seq_printf(s, "id\t\t%*ph\n", info->id_len, info->id); + seq_printf(s, "id\t\t%*ph\n", SPI_NOR_MAX_ID_LEN, nor->id); string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf)); seq_printf(s, "size\t\t%s\n", buf); seq_printf(s, "write size\t%u\n", params->writesize); diff --git a/drivers/mtd/spi-nor/gigadevice.c b/drivers/mtd/spi-nor/gigadevice.c index 119b38e6fc2a..d57ddaf1525b 100644 --- a/drivers/mtd/spi-nor/gigadevice.c +++ b/drivers/mtd/spi-nor/gigadevice.c @@ -8,19 +8,29 @@ #include "core.h" -static void gd25q256_default_init(struct spi_nor *nor) +static int +gd25q256_post_bfpt(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt) { /* - * Some manufacturer like GigaDevice may use different - * bit to set QE on different memories, so the MFR can't - * indicate the quad_enable method for this case, we need - * to set it in the default_init fixup hook. + * GD25Q256C supports the first version of JESD216 which does not define + * the Quad Enable methods. Overwrite the default Quad Enable method. + * + * GD25Q256 GENERATION | SFDP MAJOR VERSION | SFDP MINOR VERSION + * GD25Q256C | SFDP_JESD216_MAJOR | SFDP_JESD216_MINOR + * GD25Q256D | SFDP_JESD216_MAJOR | SFDP_JESD216B_MINOR + * GD25Q256E | SFDP_JESD216_MAJOR | SFDP_JESD216B_MINOR */ - nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; + if (bfpt_header->major == SFDP_JESD216_MAJOR && + bfpt_header->minor == SFDP_JESD216_MINOR) + nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; + + return 0; } static const struct spi_nor_fixups gd25q256_fixups = { - .default_init = gd25q256_default_init, + .post_bfpt = gd25q256_post_bfpt, }; static const struct flash_info gigadevice_nor_parts[] = { diff --git a/drivers/mtd/spi-nor/issi.c b/drivers/mtd/spi-nor/issi.c index 89a66a19d754..a0ddad2afffc 100644 --- a/drivers/mtd/spi-nor/issi.c +++ b/drivers/mtd/spi-nor/issi.c @@ -70,9 +70,10 @@ static const struct flash_info issi_nor_parts[] = { NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25wp128", INFO(0x9d7018, 0, 64 * 1024, 256) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 512) - NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) + { "is25wp256", INFO(0x9d7019, 0, 0, 0) + PARSE_SFDP FIXUP_FLAGS(SPI_NOR_4B_OPCODES) + FLAGS(SPI_NOR_QUAD_PP) .fixups = &is25lp256_fixups }, /* PMC */ diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c index 3c9681a3f7a3..7bb86df52f0b 100644 --- a/drivers/mtd/spi-nor/micron-st.c +++ b/drivers/mtd/spi-nor/micron-st.c @@ -52,18 +52,21 @@ static int micron_st_nor_octal_dtr_en(struct spi_nor *nor) struct spi_mem_op op; u8 *buf = nor->bouncebuf; int ret; + u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; /* Use 20 dummy cycles for memory array reads. */ *buf = 20; op = (struct spi_mem_op) - MICRON_ST_NOR_WR_ANY_REG_OP(3, SPINOR_REG_MT_CFR1V, 1, buf); + MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes, + SPINOR_REG_MT_CFR1V, 1, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); if (ret) return ret; buf[0] = SPINOR_MT_OCT_DTR; op = (struct spi_mem_op) - MICRON_ST_NOR_WR_ANY_REG_OP(3, SPINOR_REG_MT_CFR0V, 1, buf); + MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes, + SPINOR_REG_MT_CFR0V, 1, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); if (ret) return ret; @@ -98,7 +101,8 @@ static int micron_st_nor_octal_dtr_dis(struct spi_nor *nor) buf[0] = SPINOR_MT_EXSPI; buf[1] = SPINOR_REG_MT_CFR1V_DEF; op = (struct spi_mem_op) - MICRON_ST_NOR_WR_ANY_REG_OP(4, SPINOR_REG_MT_CFR0V, 2, buf); + MICRON_ST_NOR_WR_ANY_REG_OP(nor->addr_nbytes, + SPINOR_REG_MT_CFR0V, 2, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); if (ret) return ret; @@ -201,6 +205,8 @@ static const struct flash_info st_nor_parts[] = { MFR_FLAGS(USE_FSR) }, { "mt25qu256a", INFO6(0x20bb19, 0x104400, 64 * 1024, 512) + FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | + SPI_NOR_BP3_SR_BIT6) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) FIXUP_FLAGS(SPI_NOR_4B_OPCODES) MFR_FLAGS(USE_FSR) diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 2257f1b4c2e2..8434f654eca1 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -135,8 +135,7 @@ struct sfdp_4bait { /** * spi_nor_read_raw() - raw read of serial flash memory. read_opcode, * addr_nbytes and read_dummy members of the struct spi_nor - * should be previously - * set. + * should be previously set. * @nor: pointer to a 'struct spi_nor' * @addr: offset in the serial flash memory * @len: number of bytes to read @@ -1183,10 +1182,17 @@ static int spi_nor_parse_profile1(struct spi_nor *nor, dummy = round_up(dummy, 2); /* Update the fast read settings. */ + nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_8_8_8_DTR], 0, dummy, opcode, SNOR_PROTO_8_8_8_DTR); + /* + * Page Program is "Required Command" in the xSPI Profile 1.0. Update + * the params->hwcaps.mask here. + */ + nor->params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; + out: kfree(dwords); return ret; @@ -1250,6 +1256,33 @@ static void spi_nor_post_sfdp_fixups(struct spi_nor *nor) } /** + * spi_nor_check_sfdp_signature() - check for a valid SFDP signature + * @nor: pointer to a 'struct spi_nor' + * + * Used to detect if the flash supports the RDSFDP command as well as the + * presence of a valid SFDP table. + * + * Return: 0 on success, -errno otherwise. + */ +int spi_nor_check_sfdp_signature(struct spi_nor *nor) +{ + u32 signature; + int err; + + /* Get the SFDP header. */ + err = spi_nor_read_sfdp_dma_unsafe(nor, 0, sizeof(signature), + &signature); + if (err < 0) + return err; + + /* Check the SFDP signature. */ + if (le32_to_cpu(signature) != SFDP_SIGNATURE) + return -EINVAL; + + return 0; +} + +/** * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. * @nor: pointer to a 'struct spi_nor' * diff --git a/drivers/mtd/spi-nor/sfdp.h b/drivers/mtd/spi-nor/sfdp.h index bbf80d2990ab..c1969f0a2f46 100644 --- a/drivers/mtd/spi-nor/sfdp.h +++ b/drivers/mtd/spi-nor/sfdp.h @@ -107,6 +107,4 @@ struct sfdp_parameter_header { u8 id_msb; }; -int spi_nor_parse_sfdp(struct spi_nor *nor); - #endif /* __LINUX_MTD_SFDP_H */ diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 0150049007be..b621cdfd506f 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -49,11 +49,13 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) struct spi_mem_op op; u8 *buf = nor->bouncebuf; int ret; + u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; /* Use 24 dummy cycles for memory array reads. */ *buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24; op = (struct spi_mem_op) - CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR2V, 1, buf); + CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, + SPINOR_REG_CYPRESS_CFR2V, 1, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); if (ret) @@ -64,14 +66,16 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) /* Set the octal and DTR enable bits. */ buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN; op = (struct spi_mem_op) - CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR5V, 1, buf); + CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, + SPINOR_REG_CYPRESS_CFR5V, 1, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); if (ret) return ret; /* Read flash ID to make sure the switch was successful. */ - ret = spi_nor_read_id(nor, 4, 3, buf, SNOR_PROTO_8_8_8_DTR); + ret = spi_nor_read_id(nor, nor->addr_nbytes, 3, buf, + SNOR_PROTO_8_8_8_DTR); if (ret) { dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret); return ret; @@ -97,7 +101,8 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor) buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS; buf[1] = 0; op = (struct spi_mem_op) - CYPRESS_NOR_WR_ANY_REG_OP(4, SPINOR_REG_CYPRESS_CFR5V, 2, buf); + CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes, + SPINOR_REG_CYPRESS_CFR5V, 2, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); if (ret) return ret; @@ -191,7 +196,8 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) static int cypress_nor_set_page_size(struct spi_nor *nor) { struct spi_mem_op op = - CYPRESS_NOR_RD_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR3V, + CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, + SPINOR_REG_CYPRESS_CFR3V, nor->bouncebuf); int ret; @@ -275,13 +281,7 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) cypress_nor_octal_dtr_dis(nor); } -static void s28hs512t_default_init(struct spi_nor *nor) -{ - nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable; - nor->params->writesize = 16; -} - -static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor) +static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor) { /* * On older versions of the flash the xSPI Profile 1.0 table has the @@ -309,17 +309,23 @@ static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor) nor->params->rdsr_addr_nbytes = 4; } -static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor, - const struct sfdp_parameter_header *bfpt_header, - const struct sfdp_bfpt *bfpt) +static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt) { return cypress_nor_set_page_size(nor); } -static const struct spi_nor_fixups s28hs512t_fixups = { - .default_init = s28hs512t_default_init, - .post_sfdp = s28hs512t_post_sfdp_fixup, - .post_bfpt = s28hs512t_post_bfpt_fixup, +static void s28hx_t_late_init(struct spi_nor *nor) +{ + nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable; + nor->params->writesize = 16; +} + +static const struct spi_nor_fixups s28hx_t_fixups = { + .post_sfdp = s28hx_t_post_sfdp_fixup, + .post_bfpt = s28hx_t_post_bfpt_fixup, + .late_init = s28hx_t_late_init, }; static int @@ -453,10 +459,21 @@ static const struct flash_info spansion_nor_parts[] = { .fixups = &s25hx_t_fixups }, { "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1) FLAGS(SPI_NOR_NO_ERASE) }, + { "s28hl512t", INFO(0x345a1a, 0, 256 * 1024, 256) + PARSE_SFDP + .fixups = &s28hx_t_fixups, + }, + { "s28hl01gt", INFO(0x345a1b, 0, 256 * 1024, 512) + PARSE_SFDP + .fixups = &s28hx_t_fixups, + }, { "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256) - NO_SFDP_FLAGS(SECT_4K | SPI_NOR_OCTAL_DTR_READ | - SPI_NOR_OCTAL_DTR_PP) - .fixups = &s28hs512t_fixups, + PARSE_SFDP + .fixups = &s28hx_t_fixups, + }, + { "s28hs01gt", INFO(0x345b1b, 0, 256 * 1024, 512) + PARSE_SFDP + .fixups = &s28hx_t_fixups, }, }; diff --git a/drivers/mtd/spi-nor/sysfs.c b/drivers/mtd/spi-nor/sysfs.c index 9aec9d8a98ad..c09bb832b3b9 100644 --- a/drivers/mtd/spi-nor/sysfs.c +++ b/drivers/mtd/spi-nor/sysfs.c @@ -35,8 +35,10 @@ static ssize_t jedec_id_show(struct device *dev, struct spi_device *spi = to_spi_device(dev); struct spi_mem *spimem = spi_get_drvdata(spi); struct spi_nor *nor = spi_mem_get_drvdata(spimem); + const u8 *id = nor->info->id_len ? nor->info->id : nor->id; + u8 id_len = nor->info->id_len ?: SPI_NOR_MAX_ID_LEN; - return sysfs_emit(buf, "%*phN\n", nor->info->id_len, nor->info->id); + return sysfs_emit(buf, "%*phN\n", id_len, id); } static DEVICE_ATTR_RO(jedec_id); @@ -67,6 +69,21 @@ static struct bin_attribute *spi_nor_sysfs_bin_entries[] = { NULL }; +static umode_t spi_nor_sysfs_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct spi_device *spi = to_spi_device(kobj_to_dev(kobj)); + struct spi_mem *spimem = spi_get_drvdata(spi); + struct spi_nor *nor = spi_mem_get_drvdata(spimem); + + if (attr == &dev_attr_manufacturer.attr && !nor->manufacturer) + return 0; + if (attr == &dev_attr_jedec_id.attr && !nor->info->id_len && !nor->id) + return 0; + + return 0444; +} + static umode_t spi_nor_sysfs_is_bin_visible(struct kobject *kobj, struct bin_attribute *attr, int n) { @@ -82,6 +99,7 @@ static umode_t spi_nor_sysfs_is_bin_visible(struct kobject *kobj, static const struct attribute_group spi_nor_sysfs_group = { .name = "spi-nor", + .is_visible = spi_nor_sysfs_is_visible, .is_bin_visible = spi_nor_sysfs_is_bin_visible, .attrs = spi_nor_sysfs_entries, .bin_attrs = spi_nor_sysfs_bin_entries, diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index ffaa24055259..ca39acf4112c 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -133,6 +133,9 @@ static const struct flash_info winbond_nor_parts[] = { { "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) }, + { "w25q512nwq", INFO(0xef6020, 0, 0, 0) + PARSE_SFDP + OTP_INFO(256, 3, 0x1000, 0x1000) }, { "w25q512nwm", INFO(0xef8020, 0, 64 * 1024, 1024) PARSE_SFDP OTP_INFO(256, 3, 0x1000, 0x1000) }, diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index c3693bb87b4c..b2996dc987ff 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -999,7 +999,6 @@ static inline bool nanddev_io_iter_end(struct nand_device *nand, bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos); bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos); -int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos); int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos); /* ECC related functions */ diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 42218a1164f6..25765556223a 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -349,6 +349,8 @@ struct spi_nor_flash_parameter; * @bouncebuf: bounce buffer used when the buffer passed by the MTD * layer is not DMA-able * @bouncebuf_size: size of the bounce buffer + * @id: The flash's ID bytes. Always contains + * SPI_NOR_MAX_ID_LEN bytes. * @info: SPI NOR part JEDEC MFR ID and other info * @manufacturer: SPI NOR manufacturer * @addr_nbytes: number of address bytes @@ -379,6 +381,7 @@ struct spi_nor { struct spi_mem *spimem; u8 *bouncebuf; size_t bouncebuf_size; + u8 *id; const struct flash_info *info; const struct spi_nor_manufacturer *manufacturer; u8 addr_nbytes; |