MTD core:
* Dropped inactive maintainers, updated the repositories and added the IRC channel. * Debugfs functions improvements. * Initialized of more structure parameters. * Misc fixes reported by robots. MTD devices: * spear_smi: Fixed Write Burst mode * New Intel IXP4xx flash probing hook. Raw NAND core: * Useless extra checks dropped. * Updated the detection of the bad block markers position Raw NAND controller drivers: * Cadence : New driver * Brcmnand: Support for flash-dma v0 + fixes * Denali : Support for the legacy controller/chip DT representation dropped * Superfluous dev_err() calls removed SPI NOR core changes: * introduce 'struct spi_nor_controller_ops', * clean the Register Operations methods, * use dev_dbg insted of dev_err for low level info, * fix retlen handling in sst_write(), * fix silent truncations in spi_nor_read and spi_nor_read_raw(), * fix the clearing of QE bit on lock()/unlock(), * rework the disabling of the block write protection, * rework the Quad Enable methods, * make sure nor->spimem and nor->controller_ops are mutually exclusive, * set default Quad Enable method for ISSI flashes, * add support for few flashes. SPI NOR controller drivers changes: * intel-spi: - support chips without software sequencer, - add support for Intel Cannon Lake and Intel Comet Lake-H flashes. CFI core changes: * Code cleanups related useless initializers and coding style issues * Fix for a possible double free problem in cfi_cmdset_0002 * Improved error reporting and handling in cfi_cmdset_0002 core for HyperFlash -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEE9HuaYnbmDhq/XIDIJWrqGEe9VoQFAl3YPbAACgkQJWrqGEe9 VoRBOQf5AcGMw1eNrPNUW5RjyyEf/e29KZ1UKu6fD+2EFeY8qU/VYQzMCyM5sV2S B/ks8cHJ2CAD6GmiQJJP4727QFjngT8Wi/G1H5+D8juFewCYQ2QosKoohnUwsCyC Pq/QtMz2qQC9289PTaK4K3E9IygcnSztGUDkZWNolBJLMG0OShc3BeKhH45tXGwC UC1KhS79ymJbVsIJk/PQxWKUOUVN6YL8eWBMZoOdmRDTfTZeWCpCZiALzuwrE8qb pW9vOfeL9irslHVSkDAFa8zV6K3PzZGDTg3+gynXtX+Dx6buDSPDNXD4xdjxKmmW 9p4MetkgGClTUV3Cwg95OIj1C6Mgjw== =50ZW -----END PGP SIGNATURE----- Merge tag 'mtd/for-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux Pull MTD updates from Miquel Raynal: "MTD core: - drop inactive maintainers, update the repositories and add IRC channel - debugfs functions improvements - initialize more structure parameters - misc fixes reported by robots MTD devices: - spear_smi: Fixed Write Burst mode - new Intel IXP4xx flash probing hook Raw NAND core: - useless extra checks dropped - update the detection of the bad block markers position Raw NAND controller drivers: - Cadence: new driver - Brcmnand: support for flash-dma v0 + fixes - Denali: drop support for the legacy controller/chip DT representation - superfluous dev_err() calls removed SPI NOR core changes: - introduce 'struct spi_nor_controller_ops' - clean the Register Operations methods - use dev_dbg insted of dev_err for low level info - fix retlen handling in sst_write() - fix silent truncations in spi_nor_read and spi_nor_read_raw() - fix the clearing of QE bit on lock()/unlock() - rework the disabling of the block write protection - rework the Quad Enable methods - make sure nor->spimem and nor->controller_ops are mutually exclusive - set default Quad Enable method for ISSI flashes - add support for few flashes SPI NOR controller drivers changes: - intel-spi: - support chips without software sequencer - add support for Intel Cannon Lake and Intel Comet Lake-H flashes CFI core changes: - code cleanups related useless initializers and coding style issues - fix for a possible double free problem in cfi_cmdset_0002 - improved HyperFlash error reporting and handling in cfi_cmdset_0002 core" * tag 'mtd/for-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (73 commits) mtd: devices: fix mchp23k256 read and write mtd: no need to check return value of debugfs_create functions mtd: spi-nor: Set default Quad Enable method for ISSI flashes mtd: spi-nor: Add support for is25wp256 mtd: spi-nor: Add support for w25q256jw mtd: spi-nor: Move condition to avoid a NULL check mtd: spi-nor: Make sure nor->spimem and nor->controller_ops are mutually exclusive mtd: spi-nor: Rename Quad Enable methods mtd: spi-nor: Merge spansion Quad Enable methods mtd: spi-nor: Rename CR_QUAD_EN_SPAN to SR2_QUAD_EN_BIT1 mtd: spi-nor: Extend the SR Read Back test mtd: spi-nor: Rework the disabling of block write protection mtd: spi-nor: Fix clearing of QE bit on lock()/unlock() mtd: cfi_cmdset_0002: fix delayed error detection on HyperFlash mtd: cfi_cmdset_0002: only check errors when ready in cfi_check_err_status() mtd: cfi_cmdset_0002: don't free cfi->cfiq in error path of cfi_amdstd_setup() mtd: cfi_cmdset_*: kill useless 'ret' variable initializers mtd: cfi_util: use DIV_ROUND_UP() in cfi_udelay() mtd: spi-nor: Print debug message when the read back test fails mtd: spi-nor: Check all the bits written, not just the BP ones ...
This commit is contained in:
commit
1b88176b9c
|
@ -0,0 +1,53 @@
|
|||
* Cadence NAND controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "cdns,hp-nfc"
|
||||
- reg : Contains two entries, each of which is a tuple consisting of a
|
||||
physical address and length. The first entry is the address and
|
||||
length of the controller register set. The second entry is the
|
||||
address and length of the Slave DMA data port.
|
||||
- reg-names: should contain "reg" and "sdma"
|
||||
- #address-cells: should be 1. The cell encodes the chip select connection.
|
||||
- #size-cells : should be 0.
|
||||
- interrupts : The interrupt number.
|
||||
- clocks: phandle of the controller core clock (nf_clk).
|
||||
|
||||
Optional properties:
|
||||
- dmas: shall reference DMA channel associated to the NAND controller
|
||||
- cdns,board-delay-ps : Estimated Board delay. The value includes the total
|
||||
round trip delay for the signals and is used for deciding on values
|
||||
associated with data read capture. The example formula for SDR mode is
|
||||
the following:
|
||||
board delay = RE#PAD delay + PCB trace to device + PCB trace from device
|
||||
+ DQ PAD delay
|
||||
|
||||
Child nodes represent the available NAND chips.
|
||||
|
||||
Required properties of NAND chips:
|
||||
- reg: shall contain the native Chip Select ids from 0 to max supported by
|
||||
the cadence nand flash controller
|
||||
|
||||
See Documentation/devicetree/bindings/mtd/nand.txt for more details on
|
||||
generic bindings.
|
||||
|
||||
Example:
|
||||
|
||||
nand_controller: nand-controller@60000000 {
|
||||
compatible = "cdns,hp-nfc";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x60000000 0x10000>, <0x80000000 0x10000>;
|
||||
reg-names = "reg", "sdma";
|
||||
clocks = <&nf_clk>;
|
||||
cdns,board-delay-ps = <4830>;
|
||||
interrupts = <2 0>;
|
||||
nand@0 {
|
||||
reg = <0>;
|
||||
label = "nand-1";
|
||||
};
|
||||
nand@1 {
|
||||
reg = <1>;
|
||||
label = "nand-2";
|
||||
};
|
||||
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
Flash device on Intel IXP4xx SoC
|
||||
|
||||
This flash is regular CFI compatible (Intel or AMD extended) flash chips with
|
||||
specific big-endian or mixed-endian memory access pattern.
|
||||
|
||||
Required properties:
|
||||
- compatible : must be "intel,ixp4xx-flash", "cfi-flash";
|
||||
- reg : memory address for the flash chip
|
||||
- bank-width : width in bytes of flash interface, should be <2>
|
||||
|
||||
For the rest of the properties, see mtd-physmap.txt.
|
||||
|
||||
The device tree may optionally contain sub-nodes describing partitions of the
|
||||
address space. See partition.txt for more detail.
|
||||
|
||||
Example:
|
||||
|
||||
flash@50000000 {
|
||||
compatible = "intel,ixp4xx-flash", "cfi-flash";
|
||||
reg = <0x50000000 0x01000000>;
|
||||
bank-width = <2>;
|
||||
};
|
21
MAINTAINERS
21
MAINTAINERS
|
@ -3595,6 +3595,13 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/media/cdns,*.txt
|
||||
F: drivers/media/platform/cadence/cdns-csi2*
|
||||
|
||||
CADENCE NAND DRIVER
|
||||
M: Piotr Sroka <piotrs@cadence.com>
|
||||
L: linux-mtd@lists.infradead.org
|
||||
S: Maintained
|
||||
F: drivers/mtd/nand/raw/cadence-nand-controller.c
|
||||
F: Documentation/devicetree/bindings/mtd/cadence-nand-controller.txt
|
||||
|
||||
CADET FM/AM RADIO RECEIVER DRIVER
|
||||
M: Hans Verkuil <hverkuil@xs4all.nl>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
@ -10537,15 +10544,13 @@ F: include/linux/vmalloc.h
|
|||
F: mm/
|
||||
|
||||
MEMORY TECHNOLOGY DEVICES (MTD)
|
||||
M: David Woodhouse <dwmw2@infradead.org>
|
||||
M: Brian Norris <computersforpeace@gmail.com>
|
||||
M: Marek Vasut <marek.vasut@gmail.com>
|
||||
M: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
M: Richard Weinberger <richard@nod.at>
|
||||
M: Vignesh Raghavendra <vigneshr@ti.com>
|
||||
L: linux-mtd@lists.infradead.org
|
||||
W: http://www.linux-mtd.infradead.org/
|
||||
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
|
||||
C: irc://irc.oftc.net/mtd
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/fixes
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/next
|
||||
S: Maintained
|
||||
|
@ -15296,7 +15301,6 @@ F: arch/arm/boot/dts/spear*
|
|||
F: arch/arm/mach-spear/
|
||||
|
||||
SPI NOR SUBSYSTEM
|
||||
M: Marek Vasut <marek.vasut@gmail.com>
|
||||
M: Tudor Ambarus <tudor.ambarus@microchip.com>
|
||||
L: linux-mtd@lists.infradead.org
|
||||
W: http://www.linux-mtd.infradead.org/
|
||||
|
@ -16593,10 +16597,9 @@ F: drivers/media/pci/tw686x/
|
|||
|
||||
UBI FILE SYSTEM (UBIFS)
|
||||
M: Richard Weinberger <richard@nod.at>
|
||||
M: Artem Bityutskiy <dedekind1@gmail.com>
|
||||
M: Adrian Hunter <adrian.hunter@intel.com>
|
||||
L: linux-mtd@lists.infradead.org
|
||||
T: git git://git.infradead.org/ubifs-2.6.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git next
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git fixes
|
||||
W: http://www.linux-mtd.infradead.org/doc/ubifs.html
|
||||
S: Supported
|
||||
F: Documentation/filesystems/ubifs.txt
|
||||
|
@ -16711,11 +16714,11 @@ S: Maintained
|
|||
F: drivers/scsi/ufs/ufs-mediatek*
|
||||
|
||||
UNSORTED BLOCK IMAGES (UBI)
|
||||
M: Artem Bityutskiy <dedekind1@gmail.com>
|
||||
M: Richard Weinberger <richard@nod.at>
|
||||
W: http://www.linux-mtd.infradead.org/
|
||||
L: linux-mtd@lists.infradead.org
|
||||
T: git git://git.infradead.org/ubifs-2.6.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git next
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git fixes
|
||||
S: Supported
|
||||
F: drivers/mtd/ubi/
|
||||
F: include/linux/mtd/ubi.h
|
||||
|
|
|
@ -1353,7 +1353,7 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a
|
|||
{
|
||||
unsigned long cmd_addr;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
adr += chip->start;
|
||||
|
||||
|
@ -1383,7 +1383,7 @@ static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,
|
|||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
unsigned long ofs, last_end = 0;
|
||||
int chipnum;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
if (!map->virt)
|
||||
return -EINVAL;
|
||||
|
@ -1550,7 +1550,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
|
|||
{
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
map_word status, write_cmd;
|
||||
int ret=0;
|
||||
int ret;
|
||||
|
||||
adr += chip->start;
|
||||
|
||||
|
@ -1624,7 +1624,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
|
|||
{
|
||||
struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
int chipnum;
|
||||
unsigned long ofs;
|
||||
|
||||
|
@ -1871,7 +1871,7 @@ static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs,
|
|||
struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
int chipnum;
|
||||
unsigned long ofs, vec_seek, i;
|
||||
size_t len = 0;
|
||||
|
|
|
@ -123,19 +123,23 @@ static int cfi_use_status_reg(struct cfi_private *cfi)
|
|||
(extp->SoftwareFeatures & poll_mask) == CFI_POLL_STATUS_REG;
|
||||
}
|
||||
|
||||
static void cfi_check_err_status(struct map_info *map, struct flchip *chip,
|
||||
unsigned long adr)
|
||||
static int cfi_check_err_status(struct map_info *map, struct flchip *chip,
|
||||
unsigned long adr)
|
||||
{
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
map_word status;
|
||||
|
||||
if (!cfi_use_status_reg(cfi))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
|
||||
cfi->device_type, NULL);
|
||||
status = map_read(map, adr);
|
||||
|
||||
/* The error bits are invalid while the chip's busy */
|
||||
if (!map_word_bitsset(map, status, CMD(CFI_SR_DRB)))
|
||||
return 0;
|
||||
|
||||
if (map_word_bitsset(map, status, CMD(0x3a))) {
|
||||
unsigned long chipstatus = MERGESTATUS(status);
|
||||
|
||||
|
@ -151,7 +155,12 @@ static void cfi_check_err_status(struct map_info *map, struct flchip *chip,
|
|||
if (chipstatus & CFI_SR_SLSB)
|
||||
pr_err("%s sector write protected, status %lx\n",
|
||||
map->name, chipstatus);
|
||||
|
||||
/* Erase/Program status bits are set on the operation failure */
|
||||
if (chipstatus & (CFI_SR_ESB | CFI_SR_PSB))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #define DEBUG_CFI_FEATURES */
|
||||
|
@ -785,7 +794,6 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
|
|||
kfree(mtd->eraseregions);
|
||||
kfree(mtd);
|
||||
kfree(cfi->cmdset_priv);
|
||||
kfree(cfi->cfiq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -848,20 +856,16 @@ static int __xipram chip_good(struct map_info *map, struct flchip *chip,
|
|||
|
||||
if (cfi_use_status_reg(cfi)) {
|
||||
map_word ready = CMD(CFI_SR_DRB);
|
||||
map_word err = CMD(CFI_SR_PSB | CFI_SR_ESB);
|
||||
|
||||
/*
|
||||
* For chips that support status register, check device
|
||||
* ready bit and Erase/Program status bit to know if
|
||||
* operation succeeded.
|
||||
* ready bit
|
||||
*/
|
||||
cfi_send_gen_cmd(0x70, cfi->addr_unlock1, chip->start, map, cfi,
|
||||
cfi->device_type, NULL);
|
||||
curd = map_read(map, addr);
|
||||
|
||||
if (map_word_andequal(map, curd, ready, ready))
|
||||
return !map_word_bitsset(map, curd, err);
|
||||
|
||||
return 0;
|
||||
return map_word_andequal(map, curd, ready, ready);
|
||||
}
|
||||
|
||||
oldd = map_read(map, addr);
|
||||
|
@ -1699,8 +1703,11 @@ static int __xipram do_write_oneword_once(struct map_info *map,
|
|||
break;
|
||||
}
|
||||
|
||||
if (chip_good(map, chip, adr, datum))
|
||||
if (chip_good(map, chip, adr, datum)) {
|
||||
if (cfi_check_err_status(map, chip, adr))
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Latency issues. Drop the lock, wait a while and retry */
|
||||
UDELAY(map, chip, adr, 1);
|
||||
|
@ -1713,7 +1720,7 @@ static int __xipram do_write_oneword_start(struct map_info *map,
|
|||
struct flchip *chip,
|
||||
unsigned long adr, int mode)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
|
||||
|
@ -1773,7 +1780,6 @@ static int __xipram do_write_oneword_retry(struct map_info *map,
|
|||
ret = do_write_oneword_once(map, chip, adr, datum, mode, cfi);
|
||||
if (ret) {
|
||||
/* reset on all failures. */
|
||||
cfi_check_err_status(map, chip, adr);
|
||||
map_write(map, CMD(0xF0), chip->start);
|
||||
/* FIXME - should have reset delay before continuing */
|
||||
|
||||
|
@ -1791,7 +1797,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
|
|||
unsigned long adr, map_word datum,
|
||||
int mode)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
adr += chip->start;
|
||||
|
||||
|
@ -1815,7 +1821,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
|
|||
{
|
||||
struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
int chipnum;
|
||||
unsigned long ofs, chipstart;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
@ -1970,12 +1976,17 @@ static int __xipram do_write_buffer_wait(struct map_info *map,
|
|||
*/
|
||||
if (time_after(jiffies, timeo) &&
|
||||
!chip_good(map, chip, adr, datum)) {
|
||||
pr_err("MTD %s(): software timeout, address:0x%.8lx.\n",
|
||||
__func__, adr);
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chip_good(map, chip, adr, datum))
|
||||
if (chip_good(map, chip, adr, datum)) {
|
||||
if (cfi_check_err_status(map, chip, adr))
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Latency issues. Drop the lock, wait a while and retry */
|
||||
UDELAY(map, chip, adr, 1);
|
||||
|
@ -2014,7 +2025,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
|
|||
int len)
|
||||
{
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
int ret = -EIO;
|
||||
int ret;
|
||||
unsigned long cmd_adr;
|
||||
int z, words;
|
||||
map_word datum;
|
||||
|
@ -2071,12 +2082,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
|
|||
chip->word_write_time);
|
||||
|
||||
ret = do_write_buffer_wait(map, chip, adr, datum);
|
||||
if (ret) {
|
||||
cfi_check_err_status(map, chip, adr);
|
||||
if (ret)
|
||||
do_write_buffer_reset(map, chip, cfi);
|
||||
pr_err("MTD %s(): software timeout, address:0x%.8lx.\n",
|
||||
__func__, adr);
|
||||
}
|
||||
|
||||
xip_enable(map, chip, adr);
|
||||
|
||||
|
@ -2095,7 +2102,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
|
|||
struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
int chipnum;
|
||||
unsigned long ofs;
|
||||
|
||||
|
@ -2232,7 +2239,7 @@ static int do_panic_write_oneword(struct map_info *map, struct flchip *chip,
|
|||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
int retry_cnt = 0;
|
||||
map_word oldd;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
adr += chip->start;
|
||||
|
@ -2271,9 +2278,9 @@ retry:
|
|||
udelay(1);
|
||||
}
|
||||
|
||||
if (!chip_good(map, chip, adr, datum)) {
|
||||
if (!chip_good(map, chip, adr, datum) ||
|
||||
cfi_check_err_status(map, chip, adr)) {
|
||||
/* reset on all failures. */
|
||||
cfi_check_err_status(map, chip, adr);
|
||||
map_write(map, CMD(0xF0), chip->start);
|
||||
/* FIXME - should have reset delay before continuing */
|
||||
|
||||
|
@ -2307,7 +2314,7 @@ static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||
struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
unsigned long ofs, chipstart;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
int chipnum;
|
||||
|
||||
chipnum = to >> cfi->chipshift;
|
||||
|
@ -2411,7 +2418,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
|
|||
unsigned long timeo = jiffies + HZ;
|
||||
unsigned long int adr;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
int ret = 0;
|
||||
int ret;
|
||||
int retry_cnt = 0;
|
||||
|
||||
adr = cfi->addr_unlock1;
|
||||
|
@ -2467,8 +2474,11 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
|
|||
chip->erase_suspended = 0;
|
||||
}
|
||||
|
||||
if (chip_good(map, chip, adr, map_word_ff(map)))
|
||||
if (chip_good(map, chip, adr, map_word_ff(map))) {
|
||||
if (cfi_check_err_status(map, chip, adr))
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (time_after(jiffies, timeo)) {
|
||||
printk(KERN_WARNING "MTD %s(): software timeout\n",
|
||||
|
@ -2483,7 +2493,6 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
|
|||
/* Did we succeed? */
|
||||
if (ret) {
|
||||
/* reset on all failures. */
|
||||
cfi_check_err_status(map, chip, adr);
|
||||
map_write(map, CMD(0xF0), chip->start);
|
||||
/* FIXME - should have reset delay before continuing */
|
||||
|
||||
|
@ -2508,7 +2517,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
|
|||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
unsigned long timeo = jiffies + HZ;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
int ret = 0;
|
||||
int ret;
|
||||
int retry_cnt = 0;
|
||||
|
||||
adr += chip->start;
|
||||
|
@ -2564,8 +2573,11 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
|
|||
chip->erase_suspended = 0;
|
||||
}
|
||||
|
||||
if (chip_good(map, chip, adr, map_word_ff(map)))
|
||||
if (chip_good(map, chip, adr, map_word_ff(map))) {
|
||||
if (cfi_check_err_status(map, chip, adr))
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (time_after(jiffies, timeo)) {
|
||||
printk(KERN_WARNING "MTD %s(): software timeout\n",
|
||||
|
@ -2580,7 +2592,6 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
|
|||
/* Did we succeed? */
|
||||
if (ret) {
|
||||
/* reset on all failures. */
|
||||
cfi_check_err_status(map, chip, adr);
|
||||
map_write(map, CMD(0xF0), chip->start);
|
||||
/* FIXME - should have reset delay before continuing */
|
||||
|
||||
|
|
|
@ -611,7 +611,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to,
|
|||
struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
int chipnum;
|
||||
unsigned long ofs;
|
||||
|
||||
|
@ -895,7 +895,7 @@ static int cfi_staa_erase_varsize(struct mtd_info *mtd,
|
|||
{ struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
unsigned long adr, len;
|
||||
int chipnum, ret = 0;
|
||||
int chipnum, ret;
|
||||
int i, first;
|
||||
struct mtd_erase_region_info *regions = mtd->eraseregions;
|
||||
|
||||
|
@ -1132,7 +1132,7 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
|||
struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
unsigned long adr;
|
||||
int chipnum, ret = 0;
|
||||
int chipnum, ret;
|
||||
#ifdef DEBUG_LOCK_BITS
|
||||
int ofs_factor = cfi->interleave * cfi->device_type;
|
||||
#endif
|
||||
|
@ -1279,7 +1279,7 @@ static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
|||
struct map_info *map = mtd->priv;
|
||||
struct cfi_private *cfi = map->fldrv_priv;
|
||||
unsigned long adr;
|
||||
int chipnum, ret = 0;
|
||||
int chipnum, ret;
|
||||
#ifdef DEBUG_LOCK_BITS
|
||||
int ofs_factor = cfi->interleave * cfi->device_type;
|
||||
#endif
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
void cfi_udelay(int us)
|
||||
{
|
||||
if (us >= 1000) {
|
||||
msleep((us+999)/1000);
|
||||
msleep(DIV_ROUND_UP(us, 1000));
|
||||
} else {
|
||||
udelay(us);
|
||||
cond_resched();
|
||||
|
|
|
@ -64,15 +64,17 @@ static int mchp23k256_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||
struct spi_transfer transfer[2] = {};
|
||||
struct spi_message message;
|
||||
unsigned char command[MAX_CMD_SIZE];
|
||||
int ret;
|
||||
int ret, cmd_len;
|
||||
|
||||
spi_message_init(&message);
|
||||
|
||||
cmd_len = mchp23k256_cmdsz(flash);
|
||||
|
||||
command[0] = MCHP23K256_CMD_WRITE;
|
||||
mchp23k256_addr2cmd(flash, to, command);
|
||||
|
||||
transfer[0].tx_buf = command;
|
||||
transfer[0].len = mchp23k256_cmdsz(flash);
|
||||
transfer[0].len = cmd_len;
|
||||
spi_message_add_tail(&transfer[0], &message);
|
||||
|
||||
transfer[1].tx_buf = buf;
|
||||
|
@ -88,8 +90,8 @@ static int mchp23k256_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (retlen && message.actual_length > sizeof(command))
|
||||
*retlen += message.actual_length - sizeof(command);
|
||||
if (retlen && message.actual_length > cmd_len)
|
||||
*retlen += message.actual_length - cmd_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -101,16 +103,18 @@ static int mchp23k256_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||
struct spi_transfer transfer[2] = {};
|
||||
struct spi_message message;
|
||||
unsigned char command[MAX_CMD_SIZE];
|
||||
int ret;
|
||||
int ret, cmd_len;
|
||||
|
||||
spi_message_init(&message);
|
||||
|
||||
cmd_len = mchp23k256_cmdsz(flash);
|
||||
|
||||
memset(&transfer, 0, sizeof(transfer));
|
||||
command[0] = MCHP23K256_CMD_READ;
|
||||
mchp23k256_addr2cmd(flash, from, command);
|
||||
|
||||
transfer[0].tx_buf = command;
|
||||
transfer[0].len = mchp23k256_cmdsz(flash);
|
||||
transfer[0].len = cmd_len;
|
||||
spi_message_add_tail(&transfer[0], &message);
|
||||
|
||||
transfer[1].rx_buf = buf;
|
||||
|
@ -126,8 +130,8 @@ static int mchp23k256_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (retlen && message.actual_length > sizeof(command))
|
||||
*retlen += message.actual_length - sizeof(command);
|
||||
if (retlen && message.actual_length > cmd_len)
|
||||
*retlen += message.actual_length - cmd_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -592,6 +592,26 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The purpose of this function is to ensure a memcpy_toio() with byte writes
|
||||
* only. Its structure is inspired from the ARM implementation of _memcpy_toio()
|
||||
* which also does single byte writes but cannot be used here as this is just an
|
||||
* implementation detail and not part of the API. Not mentioning the comment
|
||||
* stating that _memcpy_toio() should be optimized.
|
||||
*/
|
||||
static void spear_smi_memcpy_toio_b(volatile void __iomem *dest,
|
||||
const void *src, size_t len)
|
||||
{
|
||||
const unsigned char *from = src;
|
||||
|
||||
while (len) {
|
||||
len--;
|
||||
writeb(*from, dest);
|
||||
from++;
|
||||
dest++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank,
|
||||
void __iomem *dest, const void *src, size_t len)
|
||||
{
|
||||
|
@ -614,7 +634,23 @@ static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank,
|
|||
ctrlreg1 = readl(dev->io_base + SMI_CR1);
|
||||
writel((ctrlreg1 | WB_MODE) & ~SW_MODE, dev->io_base + SMI_CR1);
|
||||
|
||||
memcpy_toio(dest, src, len);
|
||||
/*
|
||||
* In Write Burst mode (WB_MODE), the specs states that writes must be:
|
||||
* - incremental
|
||||
* - of the same size
|
||||
* The ARM implementation of memcpy_toio() will optimize the number of
|
||||
* I/O by using as much 4-byte writes as possible, surrounded by
|
||||
* 2-byte/1-byte access if:
|
||||
* - the destination is not 4-byte aligned
|
||||
* - the length is not a multiple of 4-byte.
|
||||
* Avoid this alternance of write access size by using our own 'byte
|
||||
* access' helper if at least one of the two conditions above is true.
|
||||
*/
|
||||
if (IS_ALIGNED(len, sizeof(u32)) &&
|
||||
IS_ALIGNED((uintptr_t)dest, sizeof(u32)))
|
||||
memcpy_toio(dest, src, len);
|
||||
else
|
||||
spear_smi_memcpy_toio_b(dest, src, len);
|
||||
|
||||
writel(ctrlreg1, dev->io_base + SMI_CR1);
|
||||
|
||||
|
@ -777,9 +813,6 @@ static int spear_smi_probe_config_dt(struct platform_device *pdev,
|
|||
|
||||
/* Fill structs for each subnode (flash device) */
|
||||
while ((pp = of_get_next_child(np, pp))) {
|
||||
struct spear_smi_flash_info *flash_info;
|
||||
|
||||
flash_info = &pdata->board_flash_info[i];
|
||||
pdata->np[i] = pp;
|
||||
|
||||
/* Read base-addr and size from DT */
|
||||
|
@ -933,7 +966,6 @@ static int spear_smi_probe(struct platform_device *pdev)
|
|||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
ret = -ENODEV;
|
||||
dev_err(&pdev->dev, "invalid smi irq\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
|
@ -255,7 +255,6 @@ struct stfsm_seq {
|
|||
struct stfsm {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct resource *region;
|
||||
struct mtd_info mtd;
|
||||
struct mutex lock;
|
||||
struct flash_info *info;
|
||||
|
|
|
@ -96,6 +96,17 @@ config MTD_PHYSMAP_GEMINI
|
|||
platforms, some detection and setting up parallel mode on the
|
||||
external interface.
|
||||
|
||||
config MTD_PHYSMAP_IXP4XX
|
||||
bool "Intel IXP4xx OF-based physical memory map handling"
|
||||
depends on MTD_PHYSMAP_OF
|
||||
depends on ARM
|
||||
select MTD_COMPLEX_MAPPINGS
|
||||
select MTD_CFI_BE_BYTE_SWAP if CPU_BIG_ENDIAN
|
||||
default ARCH_IXP4XX
|
||||
help
|
||||
This provides some extra DT physmap parsing for the Intel IXP4xx
|
||||
platforms, some elaborate endianness handling in particular.
|
||||
|
||||
config MTD_PHYSMAP_GPIO_ADDR
|
||||
bool "GPIO-assisted Flash Chip Support"
|
||||
depends on MTD_PHYSMAP
|
||||
|
|
|
@ -20,6 +20,7 @@ obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o
|
|||
physmap-objs-y += physmap-core.o
|
||||
physmap-objs-$(CONFIG_MTD_PHYSMAP_VERSATILE) += physmap-versatile.o
|
||||
physmap-objs-$(CONFIG_MTD_PHYSMAP_GEMINI) += physmap-gemini.o
|
||||
physmap-objs-$(CONFIG_MTD_PHYSMAP_IXP4XX) += physmap-ixp4xx.o
|
||||
physmap-objs := $(physmap-objs-y)
|
||||
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
|
||||
obj-$(CONFIG_MTD_PISMO) += pismo.o
|
||||
|
|
|
@ -86,7 +86,7 @@ static int __init init_l440gx(void)
|
|||
return -ENOMEM;
|
||||
}
|
||||
simple_map_init(&l440gx_map);
|
||||
printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt);
|
||||
pr_debug("window_addr = %p\n", l440gx_map.virt);
|
||||
|
||||
/* Setup the pm iobase resource
|
||||
* This code should move into some kind of generic bridge
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#include "physmap-gemini.h"
|
||||
#include "physmap-ixp4xx.h"
|
||||
#include "physmap-versatile.h"
|
||||
|
||||
struct physmap_flash_info {
|
||||
|
@ -370,6 +371,10 @@ static int physmap_flash_of_init(struct platform_device *dev)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = of_flash_probe_ixp4xx(dev, dp, &info->maps[i]);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = of_flash_probe_versatile(dev, dp, &info->maps[i]);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Intel IXP4xx OF physmap add-on
|
||||
* Copyright (C) 2019 Linus Walleij <linus.walleij@linaro.org>
|
||||
*
|
||||
* Based on the ixp4xx.c map driver, originally written by:
|
||||
* Intel Corporation
|
||||
* Deepak Saxena <dsaxena@mvista.com>
|
||||
* Copyright (C) 2002 Intel Corporation
|
||||
* Copyright (C) 2003-2004 MontaVista Software, Inc.
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mtd/map.h>
|
||||
#include <linux/mtd/xip.h>
|
||||
#include "physmap-ixp4xx.h"
|
||||
|
||||
/*
|
||||
* Read/write a 16 bit word from flash address 'addr'.
|
||||
*
|
||||
* When the cpu is in little-endian mode it swizzles the address lines
|
||||
* ('address coherency') so we need to undo the swizzling to ensure commands
|
||||
* and the like end up on the correct flash address.
|
||||
*
|
||||
* To further complicate matters, due to the way the expansion bus controller
|
||||
* handles 32 bit reads, the byte stream ABCD is stored on the flash as:
|
||||
* D15 D0
|
||||
* +---+---+
|
||||
* | A | B | 0
|
||||
* +---+---+
|
||||
* | C | D | 2
|
||||
* +---+---+
|
||||
* This means that on LE systems each 16 bit word must be swapped. Note that
|
||||
* this requires CONFIG_MTD_CFI_BE_BYTE_SWAP to be enabled to 'unswap' the CFI
|
||||
* data and other flash commands which are always in D7-D0.
|
||||
*/
|
||||
#ifndef CONFIG_CPU_BIG_ENDIAN
|
||||
|
||||
static inline u16 flash_read16(void __iomem *addr)
|
||||
{
|
||||
return be16_to_cpu(__raw_readw((void __iomem *)((unsigned long)addr ^ 0x2)));
|
||||
}
|
||||
|
||||
static inline void flash_write16(u16 d, void __iomem *addr)
|
||||
{
|
||||
__raw_writew(cpu_to_be16(d), (void __iomem *)((unsigned long)addr ^ 0x2));
|
||||
}
|
||||
|
||||
#define BYTE0(h) ((h) & 0xFF)
|
||||
#define BYTE1(h) (((h) >> 8) & 0xFF)
|
||||
|
||||
#else
|
||||
|
||||
static inline u16 flash_read16(const void __iomem *addr)
|
||||
{
|
||||
return __raw_readw(addr);
|
||||
}
|
||||
|
||||
static inline void flash_write16(u16 d, void __iomem *addr)
|
||||
{
|
||||
__raw_writew(d, addr);
|
||||
}
|
||||
|
||||
#define BYTE0(h) (((h) >> 8) & 0xFF)
|
||||
#define BYTE1(h) ((h) & 0xFF)
|
||||
#endif
|
||||
|
||||
static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs)
|
||||
{
|
||||
map_word val;
|
||||
|
||||
val.x[0] = flash_read16(map->virt + ofs);
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* The IXP4xx expansion bus only allows 16-bit wide acceses
|
||||
* when attached to a 16-bit wide device (such as the 28F128J3A),
|
||||
* so we can't just memcpy_fromio().
|
||||
*/
|
||||
static void ixp4xx_copy_from(struct map_info *map, void *to,
|
||||
unsigned long from, ssize_t len)
|
||||
{
|
||||
u8 *dest = (u8 *) to;
|
||||
void __iomem *src = map->virt + from;
|
||||
|
||||
if (len <= 0)
|
||||
return;
|
||||
|
||||
if (from & 1) {
|
||||
*dest++ = BYTE1(flash_read16(src-1));
|
||||
src++;
|
||||
--len;
|
||||
}
|
||||
|
||||
while (len >= 2) {
|
||||
u16 data = flash_read16(src);
|
||||
*dest++ = BYTE0(data);
|
||||
*dest++ = BYTE1(data);
|
||||
src += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
*dest++ = BYTE0(flash_read16(src));
|
||||
}
|
||||
|
||||
static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)
|
||||
{
|
||||
flash_write16(d.x[0], map->virt + adr);
|
||||
}
|
||||
|
||||
int of_flash_probe_ixp4xx(struct platform_device *pdev,
|
||||
struct device_node *np,
|
||||
struct map_info *map)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
/* Multiplatform guard */
|
||||
if (!of_device_is_compatible(np, "intel,ixp4xx-flash"))
|
||||
return 0;
|
||||
|
||||
map->read = ixp4xx_read16;
|
||||
map->write = ixp4xx_write16;
|
||||
map->copy_from = ixp4xx_copy_from;
|
||||
map->copy_to = NULL;
|
||||
|
||||
dev_info(dev, "initialized Intel IXP4xx-specific physmap control\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#include <linux/of.h>
|
||||
#include <linux/mtd/map.h>
|
||||
|
||||
#ifdef CONFIG_MTD_PHYSMAP_IXP4XX
|
||||
int of_flash_probe_ixp4xx(struct platform_device *pdev,
|
||||
struct device_node *np,
|
||||
struct map_info *map);
|
||||
#else
|
||||
static inline
|
||||
int of_flash_probe_ixp4xx(struct platform_device *pdev,
|
||||
struct device_node *np,
|
||||
struct map_info *map)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -174,7 +174,7 @@ static ssize_t mtdchar_read(struct file *file, char __user *buf, size_t count,
|
|||
break;
|
||||
case MTD_FILE_MODE_RAW:
|
||||
{
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = {};
|
||||
|
||||
ops.mode = MTD_OPS_RAW;
|
||||
ops.datbuf = kbuf;
|
||||
|
@ -268,7 +268,7 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c
|
|||
|
||||
case MTD_FILE_MODE_RAW:
|
||||
{
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = {};
|
||||
|
||||
ops.mode = MTD_OPS_RAW;
|
||||
ops.datbuf = kbuf;
|
||||
|
@ -350,7 +350,7 @@ static int mtdchar_writeoob(struct file *file, struct mtd_info *mtd,
|
|||
uint32_t __user *retp)
|
||||
{
|
||||
struct mtd_file_info *mfi = file->private_data;
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = {};
|
||||
uint32_t retlen;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -394,7 +394,7 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd,
|
|||
uint32_t __user *retp)
|
||||
{
|
||||
struct mtd_file_info *mfi = file->private_data;
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = {};
|
||||
int ret = 0;
|
||||
|
||||
if (length > 4096)
|
||||
|
@ -587,7 +587,7 @@ static int mtdchar_write_ioctl(struct mtd_info *mtd,
|
|||
struct mtd_write_req __user *argp)
|
||||
{
|
||||
struct mtd_write_req req;
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = {};
|
||||
const void __user *usr_data, *usr_oob;
|
||||
int ret;
|
||||
|
||||
|
|
|
@ -382,33 +382,21 @@ static struct dentry *dfs_dir_mtd;
|
|||
static void mtd_debugfs_populate(struct mtd_info *mtd)
|
||||
{
|
||||
struct device *dev = &mtd->dev;
|
||||
struct dentry *root, *dent;
|
||||
struct dentry *root;
|
||||
|
||||
if (IS_ERR_OR_NULL(dfs_dir_mtd))
|
||||
return;
|
||||
|
||||
root = debugfs_create_dir(dev_name(dev), dfs_dir_mtd);
|
||||
if (IS_ERR_OR_NULL(root)) {
|
||||
dev_dbg(dev, "won't show data in debugfs\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mtd->dbg.dfs_dir = root;
|
||||
|
||||
if (mtd->dbg.partid) {
|
||||
dent = debugfs_create_file("partid", 0400, root, mtd,
|
||||
&mtd_partid_debug_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
dev_err(dev, "can't create debugfs entry for partid\n");
|
||||
}
|
||||
if (mtd->dbg.partid)
|
||||
debugfs_create_file("partid", 0400, root, mtd,
|
||||
&mtd_partid_debug_fops);
|
||||
|
||||
if (mtd->dbg.partname) {
|
||||
dent = debugfs_create_file("partname", 0400, root, mtd,
|
||||
&mtd_partname_debug_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
dev_err(dev,
|
||||
"can't create debugfs entry for partname\n");
|
||||
}
|
||||
if (mtd->dbg.partname)
|
||||
debugfs_create_file("partname", 0400, root, mtd,
|
||||
&mtd_partname_debug_fops);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_MMU
|
||||
|
|
|
@ -1257,7 +1257,6 @@ DEFINE_SHOW_ATTRIBUTE(mtdswap);
|
|||
static int mtdswap_add_debugfs(struct mtdswap_dev *d)
|
||||
{
|
||||
struct dentry *root = d->mtd->dbg.dfs_dir;
|
||||
struct dentry *dent;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_DEBUG_FS))
|
||||
return 0;
|
||||
|
@ -1265,12 +1264,7 @@ static int mtdswap_add_debugfs(struct mtdswap_dev *d)
|
|||
if (IS_ERR_OR_NULL(root))
|
||||
return -1;
|
||||
|
||||
dent = debugfs_create_file("mtdswap_stats", S_IRUSR, root, d,
|
||||
&mtdswap_fops);
|
||||
if (!dent) {
|
||||
dev_err(d->dev, "debugfs_create_file failed\n");
|
||||
return -1;
|
||||
}
|
||||
debugfs_create_file("mtdswap_stats", S_IRUSR, root, d, &mtdswap_fops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -450,6 +450,13 @@ config MTD_NAND_PLATFORM
|
|||
devices. You will need to provide platform-specific functions
|
||||
via platform_data.
|
||||
|
||||
config MTD_NAND_CADENCE
|
||||
tristate "Support Cadence NAND (HPNFC) controller"
|
||||
depends on OF || COMPILE_TEST
|
||||
help
|
||||
Enable the driver for NAND flash on platforms using a Cadence NAND
|
||||
controller.
|
||||
|
||||
comment "Misc"
|
||||
|
||||
config MTD_SM_COMMON
|
||||
|
|
|
@ -57,6 +57,7 @@ obj-$(CONFIG_MTD_NAND_MXIC) += mxic_nand.o
|
|||
obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_CADENCE) += cadence-nand-controller.o
|
||||
|
||||
nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
|
||||
nand-objs += nand_onfi.o
|
||||
|
|
|
@ -117,6 +117,18 @@ enum flash_dma_reg {
|
|||
FLASH_DMA_CURRENT_DESC_EXT,
|
||||
};
|
||||
|
||||
/* flash_dma registers v0*/
|
||||
static const u16 flash_dma_regs_v0[] = {
|
||||
[FLASH_DMA_REVISION] = 0x00,
|
||||
[FLASH_DMA_FIRST_DESC] = 0x04,
|
||||
[FLASH_DMA_CTRL] = 0x08,
|
||||
[FLASH_DMA_MODE] = 0x0c,
|
||||
[FLASH_DMA_STATUS] = 0x10,
|
||||
[FLASH_DMA_INTERRUPT_DESC] = 0x14,
|
||||
[FLASH_DMA_ERROR_STATUS] = 0x18,
|
||||
[FLASH_DMA_CURRENT_DESC] = 0x1c,
|
||||
};
|
||||
|
||||
/* flash_dma registers v1*/
|
||||
static const u16 flash_dma_regs_v1[] = {
|
||||
[FLASH_DMA_REVISION] = 0x00,
|
||||
|
@ -597,6 +609,8 @@ static void brcmnand_flash_dma_revision_init(struct brcmnand_controller *ctrl)
|
|||
/* flash_dma register offsets */
|
||||
if (ctrl->nand_version >= 0x0703)
|
||||
ctrl->flash_dma_offsets = flash_dma_regs_v4;
|
||||
else if (ctrl->nand_version == 0x0602)
|
||||
ctrl->flash_dma_offsets = flash_dma_regs_v0;
|
||||
else
|
||||
ctrl->flash_dma_offsets = flash_dma_regs_v1;
|
||||
}
|
||||
|
@ -918,7 +932,7 @@ static inline void disable_ctrl_irqs(struct brcmnand_controller *ctrl)
|
|||
return;
|
||||
|
||||
if (has_flash_dma(ctrl)) {
|
||||
ctrl->flash_dma_base = 0;
|
||||
ctrl->flash_dma_base = NULL;
|
||||
disable_irq(ctrl->dma_irq);
|
||||
}
|
||||
|
||||
|
@ -1673,8 +1687,11 @@ static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc)
|
|||
|
||||
flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC, lower_32_bits(desc));
|
||||
(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC);
|
||||
flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC_EXT, upper_32_bits(desc));
|
||||
(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC_EXT);
|
||||
if (ctrl->nand_version > 0x0602) {
|
||||
flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC_EXT,
|
||||
upper_32_bits(desc));
|
||||
(void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC_EXT);
|
||||
}
|
||||
|
||||
/* Start FLASH_DMA engine */
|
||||
ctrl->dma_pending = true;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -102,47 +102,6 @@ static int denali_dt_chip_init(struct denali_controller *denali,
|
|||
return denali_chip_init(denali, dchip);
|
||||
}
|
||||
|
||||
/* Backward compatibility for old platforms */
|
||||
static int denali_dt_legacy_chip_init(struct denali_controller *denali)
|
||||
{
|
||||
struct denali_chip *dchip;
|
||||
int nsels, i;
|
||||
|
||||
nsels = denali->nbanks;
|
||||
|
||||
dchip = devm_kzalloc(denali->dev, struct_size(dchip, sels, nsels),
|
||||
GFP_KERNEL);
|
||||
if (!dchip)
|
||||
return -ENOMEM;
|
||||
|
||||
dchip->nsels = nsels;
|
||||
|
||||
for (i = 0; i < nsels; i++)
|
||||
dchip->sels[i].bank = i;
|
||||
|
||||
nand_set_flash_node(&dchip->chip, denali->dev->of_node);
|
||||
|
||||
return denali_chip_init(denali, dchip);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the DT binding.
|
||||
* The new binding expects chip subnodes in the controller node.
|
||||
* So, #address-cells = <1>; #size-cells = <0>; are required.
|
||||
* Check the #size-cells to distinguish the binding.
|
||||
*/
|
||||
static bool denali_dt_is_legacy_binding(struct device_node *np)
|
||||
{
|
||||
u32 cells;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(np, "#size-cells", &cells);
|
||||
if (ret)
|
||||
return true;
|
||||
|
||||
return cells != 0;
|
||||
}
|
||||
|
||||
static int denali_dt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -167,10 +126,8 @@ static int denali_dt_probe(struct platform_device *pdev)
|
|||
|
||||
denali->dev = dev;
|
||||
denali->irq = platform_get_irq(pdev, 0);
|
||||
if (denali->irq < 0) {
|
||||
dev_err(dev, "no irq defined\n");
|
||||
if (denali->irq < 0)
|
||||
return denali->irq;
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg");
|
||||
denali->reg = devm_ioremap_resource(dev, res);
|
||||
|
@ -213,17 +170,11 @@ static int denali_dt_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto out_disable_clk_ecc;
|
||||
|
||||
if (denali_dt_is_legacy_binding(dev->of_node)) {
|
||||
ret = denali_dt_legacy_chip_init(denali);
|
||||
if (ret)
|
||||
for_each_child_of_node(dev->of_node, np) {
|
||||
ret = denali_dt_chip_init(denali, np);
|
||||
if (ret) {
|
||||
of_node_put(np);
|
||||
goto out_remove_denali;
|
||||
} else {
|
||||
for_each_child_of_node(dev->of_node, np) {
|
||||
ret = denali_dt_chip_init(denali, np);
|
||||
if (ret) {
|
||||
of_node_put(np);
|
||||
goto out_remove_denali;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -751,10 +751,8 @@ static int hisi_nfc_probe(struct platform_device *pdev)
|
|||
mtd = nand_to_mtd(chip);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "no IRQ resource defined\n");
|
||||
if (irq < 0)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
host->iobase = devm_ioremap_resource(dev, res);
|
||||
|
|
|
@ -773,7 +773,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
|||
|
||||
host->irq = platform_get_irq(pdev, 0);
|
||||
if (host->irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get platform irq\n");
|
||||
res = -EINVAL;
|
||||
goto release_dma_chan;
|
||||
}
|
||||
|
|
|
@ -2862,10 +2862,8 @@ static int marvell_nfc_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(nfc->regs);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to retrieve irq\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
nfc->core_clk = devm_clk_get(&pdev->dev, "core");
|
||||
|
||||
|
|
|
@ -1399,10 +1399,8 @@ static int meson_nfc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "no NFC IRQ resource\n");
|
||||
if (irq < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = meson_nfc_clk_init(nfc);
|
||||
if (ret) {
|
||||
|
|
|
@ -527,10 +527,8 @@ static int mtk_ecc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to get irq: %d\n", irq);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = dma_set_mask(dev, DMA_BIT_MASK(32));
|
||||
if (ret) {
|
||||
|
|
|
@ -1540,7 +1540,6 @@ static int mtk_nfc_probe(struct platform_device *pdev)
|
|||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "no nfi irq resource\n");
|
||||
ret = -EINVAL;
|
||||
goto clk_disable;
|
||||
}
|
||||
|
|
|
@ -524,10 +524,8 @@ static int mxic_nfc_probe(struct platform_device *pdev)
|
|||
nand_chip->controller = &nfc->controller;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to retrieve irq\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
mxic_nfc_hw_init(nfc);
|
||||
|
||||
|
|
|
@ -292,12 +292,16 @@ int nand_bbm_get_next_page(struct nand_chip *chip, int page)
|
|||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
int last_page = ((mtd->erasesize - mtd->writesize) >>
|
||||
chip->page_shift) & chip->pagemask;
|
||||
unsigned int bbm_flags = NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE
|
||||
| NAND_BBM_LASTPAGE;
|
||||
|
||||
if (page == 0 && !(chip->options & bbm_flags))
|
||||
return 0;
|
||||
if (page == 0 && chip->options & NAND_BBM_FIRSTPAGE)
|
||||
return 0;
|
||||
else if (page <= 1 && chip->options & NAND_BBM_SECONDPAGE)
|
||||
if (page <= 1 && chip->options & NAND_BBM_SECONDPAGE)
|
||||
return 1;
|
||||
else if (page <= last_page && chip->options & NAND_BBM_LASTPAGE)
|
||||
if (page <= last_page && chip->options & NAND_BBM_LASTPAGE)
|
||||
return last_page;
|
||||
|
||||
return -EINVAL;
|
||||
|
|
|
@ -446,8 +446,10 @@ static int micron_nand_init(struct nand_chip *chip)
|
|||
if (ret)
|
||||
goto err_free_manuf_data;
|
||||
|
||||
chip->options |= NAND_BBM_FIRSTPAGE;
|
||||
|
||||
if (mtd->writesize == 2048)
|
||||
chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
|
||||
chip->options |= NAND_BBM_SECONDPAGE;
|
||||
|
||||
ondie = micron_supports_on_die_ecc(chip);
|
||||
|
||||
|
|
|
@ -1967,10 +1967,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
|
|||
|
||||
case NAND_OMAP_PREFETCH_IRQ:
|
||||
info->gpmc_irq_fifo = platform_get_irq(info->pdev, 0);
|
||||
if (info->gpmc_irq_fifo <= 0) {
|
||||
dev_err(dev, "Error getting fifo IRQ\n");
|
||||
if (info->gpmc_irq_fifo <= 0)
|
||||
return -ENODEV;
|
||||
}
|
||||
err = devm_request_irq(dev, info->gpmc_irq_fifo,
|
||||
omap_nand_irq, IRQF_SHARED,
|
||||
"gpmc-nand-fifo", info);
|
||||
|
@ -1982,10 +1980,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
|
|||
}
|
||||
|
||||
info->gpmc_irq_count = platform_get_irq(info->pdev, 1);
|
||||
if (info->gpmc_irq_count <= 0) {
|
||||
dev_err(dev, "Error getting IRQ count\n");
|
||||
if (info->gpmc_irq_count <= 0)
|
||||
return -ENODEV;
|
||||
}
|
||||
err = devm_request_irq(dev, info->gpmc_irq_count,
|
||||
omap_nand_irq, IRQF_SHARED,
|
||||
"gpmc-nand-count", info);
|
||||
|
|
|
@ -1129,10 +1129,8 @@ static int flctl_probe(struct platform_device *pdev)
|
|||
flctl->fifo = res->start + 0x24; /* FLDTFIFO */
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get flste irq data: %d\n", irq);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, flctl_handle_flste, IRQF_SHARED,
|
||||
"flste", flctl);
|
||||
|
|
|
@ -1880,11 +1880,8 @@ static int stm32_fmc2_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
if (irq != -EPROBE_DEFER)
|
||||
dev_err(dev, "IRQ error missing or invalid\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, irq, stm32_fmc2_irq, 0,
|
||||
dev_name(dev), fmc2);
|
||||
|
|
|
@ -2071,10 +2071,8 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(nfc->regs);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to retrieve irq\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
nfc->ahb_clk = devm_clk_get(dev, "ahb");
|
||||
if (IS_ERR(nfc->ahb_clk)) {
|
||||
|
|
|
@ -320,7 +320,8 @@ static void aspeed_smc_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
|
|||
mutex_unlock(&chip->controller->mutex);
|
||||
}
|
||||
|
||||
static int aspeed_smc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
||||
static int aspeed_smc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct aspeed_smc_chip *chip = nor->priv;
|
||||
|
||||
|
@ -331,8 +332,8 @@ static int aspeed_smc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int aspeed_smc_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
|
||||
int len)
|
||||
static int aspeed_smc_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct aspeed_smc_chip *chip = nor->priv;
|
||||
|
||||
|
@ -746,6 +747,15 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_nor_controller_ops aspeed_smc_controller_ops = {
|
||||
.prepare = aspeed_smc_prep,
|
||||
.unprepare = aspeed_smc_unprep,
|
||||
.read_reg = aspeed_smc_read_reg,
|
||||
.write_reg = aspeed_smc_write_reg,
|
||||
.read = aspeed_smc_read_user,
|
||||
.write = aspeed_smc_write_user,
|
||||
};
|
||||
|
||||
static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
|
||||
struct device_node *np, struct resource *r)
|
||||
{
|
||||
|
@ -805,12 +815,7 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
|
|||
nor->dev = dev;
|
||||
nor->priv = chip;
|
||||
spi_nor_set_flash_node(nor, child);
|
||||
nor->read = aspeed_smc_read_user;
|
||||
nor->write = aspeed_smc_write_user;
|
||||
nor->read_reg = aspeed_smc_read_reg;
|
||||
nor->write_reg = aspeed_smc_write_reg;
|
||||
nor->prepare = aspeed_smc_prep;
|
||||
nor->unprepare = aspeed_smc_unprep;
|
||||
nor->controller_ops = &aspeed_smc_controller_ops;
|
||||
|
||||
ret = aspeed_smc_chip_setup_init(chip, r);
|
||||
if (ret)
|
||||
|
|
|
@ -285,7 +285,7 @@ static irqreturn_t cqspi_irq_handler(int this_irq, void *dev)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static unsigned int cqspi_calc_rdreg(struct spi_nor *nor, const u8 opcode)
|
||||
static unsigned int cqspi_calc_rdreg(struct spi_nor *nor)
|
||||
{
|
||||
struct cqspi_flash_pdata *f_pdata = nor->priv;
|
||||
u32 rdreg = 0;
|
||||
|
@ -354,27 +354,27 @@ static int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg)
|
|||
return cqspi_wait_idle(cqspi);
|
||||
}
|
||||
|
||||
static int cqspi_command_read(struct spi_nor *nor,
|
||||
const u8 *txbuf, const unsigned n_tx,
|
||||
u8 *rxbuf, const unsigned n_rx)
|
||||
static int cqspi_command_read(struct spi_nor *nor, u8 opcode,
|
||||
u8 *rxbuf, size_t n_rx)
|
||||
{
|
||||
struct cqspi_flash_pdata *f_pdata = nor->priv;
|
||||
struct cqspi_st *cqspi = f_pdata->cqspi;
|
||||
void __iomem *reg_base = cqspi->iobase;
|
||||
unsigned int rdreg;
|
||||
unsigned int reg;
|
||||
unsigned int read_len;
|
||||
size_t read_len;
|
||||
int status;
|
||||
|
||||
if (!n_rx || n_rx > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) {
|
||||
dev_err(nor->dev, "Invalid input argument, len %d rxbuf 0x%p\n",
|
||||
dev_err(nor->dev,
|
||||
"Invalid input argument, len %zu rxbuf 0x%p\n",
|
||||
n_rx, rxbuf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reg = txbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
|
||||
reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
|
||||
|
||||
rdreg = cqspi_calc_rdreg(nor, txbuf[0]);
|
||||
rdreg = cqspi_calc_rdreg(nor);
|
||||
writel(rdreg, reg_base + CQSPI_REG_RD_INSTR);
|
||||
|
||||
reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
|
||||
|
@ -404,19 +404,19 @@ static int cqspi_command_read(struct spi_nor *nor,
|
|||
}
|
||||
|
||||
static int cqspi_command_write(struct spi_nor *nor, const u8 opcode,
|
||||
const u8 *txbuf, const unsigned n_tx)
|
||||
const u8 *txbuf, size_t n_tx)
|
||||
{
|
||||
struct cqspi_flash_pdata *f_pdata = nor->priv;
|
||||
struct cqspi_st *cqspi = f_pdata->cqspi;
|
||||
void __iomem *reg_base = cqspi->iobase;
|
||||
unsigned int reg;
|
||||
unsigned int data;
|
||||
u32 write_len;
|
||||
size_t write_len;
|
||||
int ret;
|
||||
|
||||
if (n_tx > CQSPI_STIG_DATA_LEN_MAX || (n_tx && !txbuf)) {
|
||||
dev_err(nor->dev,
|
||||
"Invalid input argument, cmdlen %d txbuf 0x%p\n",
|
||||
"Invalid input argument, cmdlen %zu txbuf 0x%p\n",
|
||||
n_tx, txbuf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -470,7 +470,7 @@ static int cqspi_read_setup(struct spi_nor *nor)
|
|||
unsigned int reg;
|
||||
|
||||
reg = nor->read_opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
|
||||
reg |= cqspi_calc_rdreg(nor, nor->read_opcode);
|
||||
reg |= cqspi_calc_rdreg(nor);
|
||||
|
||||
/* Setup dummy clock cycles */
|
||||
dummy_clk = nor->read_dummy;
|
||||
|
@ -603,7 +603,7 @@ static int cqspi_write_setup(struct spi_nor *nor)
|
|||
/* Set opcode. */
|
||||
reg = nor->program_opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB;
|
||||
writel(reg, reg_base + CQSPI_REG_WR_INSTR);
|
||||
reg = cqspi_calc_rdreg(nor, nor->program_opcode);
|
||||
reg = cqspi_calc_rdreg(nor);
|
||||
writel(reg, reg_base + CQSPI_REG_RD_INSTR);
|
||||
|
||||
reg = readl(reg_base + CQSPI_REG_SIZE);
|
||||
|
@ -1050,7 +1050,7 @@ static int cqspi_erase(struct spi_nor *nor, loff_t offs)
|
|||
return ret;
|
||||
|
||||
/* Send write enable, then erase commands. */
|
||||
ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
|
||||
ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1080,18 +1080,19 @@ static void cqspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
|
|||
mutex_unlock(&cqspi->bus_mutex);
|
||||
}
|
||||
|
||||
static int cqspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
||||
static int cqspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, size_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = cqspi_set_protocol(nor, 0);
|
||||
if (!ret)
|
||||
ret = cqspi_command_read(nor, &opcode, 1, buf, len);
|
||||
ret = cqspi_command_read(nor, opcode, buf, len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cqspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
||||
static int cqspi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -1216,6 +1217,16 @@ static void cqspi_request_mmap_dma(struct cqspi_st *cqspi)
|
|||
init_completion(&cqspi->rx_dma_complete);
|
||||
}
|
||||
|
||||
static const struct spi_nor_controller_ops cqspi_controller_ops = {
|
||||
.prepare = cqspi_prep,
|
||||
.unprepare = cqspi_unprep,
|
||||
.read_reg = cqspi_read_reg,
|
||||
.write_reg = cqspi_write_reg,
|
||||
.read = cqspi_read,
|
||||
.write = cqspi_write,
|
||||
.erase = cqspi_erase,
|
||||
};
|
||||
|
||||
static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
|
||||
{
|
||||
struct platform_device *pdev = cqspi->pdev;
|
||||
|
@ -1265,14 +1276,7 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
|
|||
nor->dev = dev;
|
||||
spi_nor_set_flash_node(nor, np);
|
||||
nor->priv = f_pdata;
|
||||
|
||||
nor->read_reg = cqspi_read_reg;
|
||||
nor->write_reg = cqspi_write_reg;
|
||||
nor->read = cqspi_read;
|
||||
nor->write = cqspi_write;
|
||||
nor->erase = cqspi_erase;
|
||||
nor->prepare = cqspi_prep;
|
||||
nor->unprepare = cqspi_unprep;
|
||||
nor->controller_ops = &cqspi_controller_ops;
|
||||
|
||||
mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d",
|
||||
dev_name(dev), cs);
|
||||
|
@ -1366,10 +1370,8 @@ static int cqspi_probe(struct platform_device *pdev)
|
|||
|
||||
/* Obtain IRQ line. */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "Cannot obtain IRQ.\n");
|
||||
if (irq < 0)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
|
|
|
@ -177,7 +177,7 @@ static void hisi_spi_nor_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
|
|||
}
|
||||
|
||||
static int hisi_spi_nor_op_reg(struct spi_nor *nor,
|
||||
u8 opcode, int len, u8 optype)
|
||||
u8 opcode, size_t len, u8 optype)
|
||||
{
|
||||
struct hifmc_priv *priv = nor->priv;
|
||||
struct hifmc_host *host = priv->host;
|
||||
|
@ -200,7 +200,7 @@ static int hisi_spi_nor_op_reg(struct spi_nor *nor,
|
|||
}
|
||||
|
||||
static int hisi_spi_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
|
||||
int len)
|
||||
size_t len)
|
||||
{
|
||||
struct hifmc_priv *priv = nor->priv;
|
||||
struct hifmc_host *host = priv->host;
|
||||
|
@ -215,7 +215,7 @@ static int hisi_spi_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
|
|||
}
|
||||
|
||||
static int hisi_spi_nor_write_reg(struct spi_nor *nor, u8 opcode,
|
||||
u8 *buf, int len)
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
struct hifmc_priv *priv = nor->priv;
|
||||
struct hifmc_host *host = priv->host;
|
||||
|
@ -311,6 +311,15 @@ static ssize_t hisi_spi_nor_write(struct spi_nor *nor, loff_t to,
|
|||
return len;
|
||||
}
|
||||
|
||||
static const struct spi_nor_controller_ops hisi_controller_ops = {
|
||||
.prepare = hisi_spi_nor_prep,
|
||||
.unprepare = hisi_spi_nor_unprep,
|
||||
.read_reg = hisi_spi_nor_read_reg,
|
||||
.write_reg = hisi_spi_nor_write_reg,
|
||||
.read = hisi_spi_nor_read,
|
||||
.write = hisi_spi_nor_write,
|
||||
};
|
||||
|
||||
/**
|
||||
* Get spi flash device information and register it as a mtd device.
|
||||
*/
|
||||
|
@ -357,14 +366,8 @@ static int hisi_spi_nor_register(struct device_node *np,
|
|||
}
|
||||
priv->host = host;
|
||||
nor->priv = priv;
|
||||
nor->controller_ops = &hisi_controller_ops;
|
||||
|
||||
nor->prepare = hisi_spi_nor_prep;
|
||||
nor->unprepare = hisi_spi_nor_unprep;
|
||||
nor->read_reg = hisi_spi_nor_read_reg;
|
||||
nor->write_reg = hisi_spi_nor_write_reg;
|
||||
nor->read = hisi_spi_nor_read;
|
||||
nor->write = hisi_spi_nor_write;
|
||||
nor->erase = NULL;
|
||||
ret = spi_nor_scan(nor, NULL, &hwcaps);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
@ -20,6 +20,10 @@ static const struct intel_spi_boardinfo bxt_info = {
|
|||
.type = INTEL_SPI_BXT,
|
||||
};
|
||||
|
||||
static const struct intel_spi_boardinfo cnl_info = {
|
||||
.type = INTEL_SPI_CNL,
|
||||
};
|
||||
|
||||
static int intel_spi_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
|
@ -61,6 +65,7 @@ static void intel_spi_pci_remove(struct pci_dev *pdev)
|
|||
|
||||
static const struct pci_device_id intel_spi_pci_ids[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
|
||||
|
@ -68,6 +73,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
|
|||
{ PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids);
|
||||
|
|
|
@ -108,6 +108,10 @@
|
|||
#define BXT_FREG_NUM 12
|
||||
#define BXT_PR_NUM 6
|
||||
|
||||
#define CNL_PR 0x84
|
||||
#define CNL_FREG_NUM 6
|
||||
#define CNL_PR_NUM 5
|
||||
|
||||
#define LVSCC 0xc4
|
||||
#define UVSCC 0xc8
|
||||
#define ERASE_OPCODE_SHIFT 8
|
||||
|
@ -187,12 +191,16 @@ static void intel_spi_dump_regs(struct intel_spi *ispi)
|
|||
dev_dbg(ispi->dev, "PR(%d)=0x%08x\n", i,
|
||||
readl(ispi->pregs + PR(i)));
|
||||
|
||||
value = readl(ispi->sregs + SSFSTS_CTL);
|
||||
dev_dbg(ispi->dev, "SSFSTS_CTL=0x%08x\n", value);
|
||||
dev_dbg(ispi->dev, "PREOP_OPTYPE=0x%08x\n",
|
||||
readl(ispi->sregs + PREOP_OPTYPE));
|
||||
dev_dbg(ispi->dev, "OPMENU0=0x%08x\n", readl(ispi->sregs + OPMENU0));
|
||||
dev_dbg(ispi->dev, "OPMENU1=0x%08x\n", readl(ispi->sregs + OPMENU1));
|
||||
if (ispi->sregs) {
|
||||
value = readl(ispi->sregs + SSFSTS_CTL);
|
||||
dev_dbg(ispi->dev, "SSFSTS_CTL=0x%08x\n", value);
|
||||
dev_dbg(ispi->dev, "PREOP_OPTYPE=0x%08x\n",
|
||||
readl(ispi->sregs + PREOP_OPTYPE));
|
||||
dev_dbg(ispi->dev, "OPMENU0=0x%08x\n",
|
||||
readl(ispi->sregs + OPMENU0));
|
||||
dev_dbg(ispi->dev, "OPMENU1=0x%08x\n",
|
||||
readl(ispi->sregs + OPMENU1));
|
||||
}
|
||||
|
||||
if (ispi->info->type == INTEL_SPI_BYT)
|
||||
dev_dbg(ispi->dev, "BCR=0x%08x\n", readl(ispi->base + BYT_BCR));
|
||||
|
@ -340,6 +348,13 @@ static int intel_spi_init(struct intel_spi *ispi)
|
|||
ispi->erase_64k = true;
|
||||
break;
|
||||
|
||||
case INTEL_SPI_CNL:
|
||||
ispi->sregs = NULL;
|
||||
ispi->pregs = ispi->base + CNL_PR;
|
||||
ispi->nregions = CNL_FREG_NUM;
|
||||
ispi->pr_num = CNL_PR_NUM;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -367,6 +382,11 @@ static int intel_spi_init(struct intel_spi *ispi)
|
|||
!(uvscc & ERASE_64K_OPCODE_MASK))
|
||||
ispi->erase_64k = false;
|
||||
|
||||
if (ispi->sregs == NULL && (ispi->swseq_reg || ispi->swseq_erase)) {
|
||||
dev_err(ispi->dev, "software sequencer not supported, but required\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some controllers can only do basic operations using hardware
|
||||
* sequencer. All other operations are supposed to be carried out
|
||||
|
@ -383,7 +403,7 @@ static int intel_spi_init(struct intel_spi *ispi)
|
|||
val = readl(ispi->base + HSFSTS_CTL);
|
||||
ispi->locked = !!(val & HSFSTS_CTL_FLOCKDN);
|
||||
|
||||
if (ispi->locked) {
|
||||
if (ispi->locked && ispi->sregs) {
|
||||
/*
|
||||
* BIOS programs allowed opcodes and then locks down the
|
||||
* register. So read back what opcodes it decided to support.
|
||||
|
@ -426,7 +446,7 @@ static int intel_spi_opcode_index(struct intel_spi *ispi, u8 opcode, int optype)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, int len)
|
||||
static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len)
|
||||
{
|
||||
u32 val, status;
|
||||
int ret;
|
||||
|
@ -469,7 +489,7 @@ static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, int len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, int len,
|
||||
static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len,
|
||||
int optype)
|
||||
{
|
||||
u32 val = 0, status;
|
||||
|
@ -535,7 +555,8 @@ static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, int len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int intel_spi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
||||
static int intel_spi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct intel_spi *ispi = nor->priv;
|
||||
int ret;
|
||||
|
@ -555,7 +576,8 @@ static int intel_spi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
|||
return intel_spi_read_block(ispi, buf, len);
|
||||
}
|
||||
|
||||
static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
||||
static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct intel_spi *ispi = nor->priv;
|
||||
int ret;
|
||||
|
@ -864,6 +886,14 @@ static void intel_spi_fill_partition(struct intel_spi *ispi,
|
|||
}
|
||||
}
|
||||
|
||||
static const struct spi_nor_controller_ops intel_spi_controller_ops = {
|
||||
.read_reg = intel_spi_read_reg,
|
||||
.write_reg = intel_spi_write_reg,
|
||||
.read = intel_spi_read,
|
||||
.write = intel_spi_write,
|
||||
.erase = intel_spi_erase,
|
||||
};
|
||||
|
||||
struct intel_spi *intel_spi_probe(struct device *dev,
|
||||
struct resource *mem, const struct intel_spi_boardinfo *info)
|
||||
{
|
||||
|
@ -897,11 +927,7 @@ struct intel_spi *intel_spi_probe(struct device *dev,
|
|||
|
||||
ispi->nor.dev = ispi->dev;
|
||||
ispi->nor.priv = ispi;
|
||||
ispi->nor.read_reg = intel_spi_read_reg;
|
||||
ispi->nor.write_reg = intel_spi_write_reg;
|
||||
ispi->nor.read = intel_spi_read;
|
||||
ispi->nor.write = intel_spi_write;
|
||||
ispi->nor.erase = intel_spi_erase;
|
||||
ispi->nor.controller_ops = &intel_spi_controller_ops;
|
||||
|
||||
ret = spi_nor_scan(&ispi->nor, NULL, &hwcaps);
|
||||
if (ret) {
|
||||
|
|
|
@ -151,9 +151,9 @@ static int mtk_nor_execute_cmd(struct mtk_nor *mtk_nor, u8 cmdval)
|
|||
}
|
||||
|
||||
static int mtk_nor_do_tx_rx(struct mtk_nor *mtk_nor, u8 op,
|
||||
u8 *tx, int txlen, u8 *rx, int rxlen)
|
||||
const u8 *tx, size_t txlen, u8 *rx, size_t rxlen)
|
||||
{
|
||||
int len = 1 + txlen + rxlen;
|
||||
size_t len = 1 + txlen + rxlen;
|
||||
int i, ret, idx;
|
||||
|
||||
if (len > MTK_NOR_MAX_SHIFT)
|
||||
|
@ -193,7 +193,7 @@ static int mtk_nor_do_tx_rx(struct mtk_nor *mtk_nor, u8 op,
|
|||
}
|
||||
|
||||
/* Do a WRSR (Write Status Register) command */
|
||||
static int mtk_nor_wr_sr(struct mtk_nor *mtk_nor, u8 sr)
|
||||
static int mtk_nor_wr_sr(struct mtk_nor *mtk_nor, const u8 sr)
|
||||
{
|
||||
writeb(sr, mtk_nor->base + MTK_NOR_PRGDATA5_REG);
|
||||
writeb(8, mtk_nor->base + MTK_NOR_CNT_REG);
|
||||
|
@ -354,7 +354,7 @@ static ssize_t mtk_nor_write(struct spi_nor *nor, loff_t to, size_t len,
|
|||
return len;
|
||||
}
|
||||
|
||||
static int mtk_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
||||
static int mtk_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, size_t len)
|
||||
{
|
||||
int ret;
|
||||
struct mtk_nor *mtk_nor = nor->priv;
|
||||
|
@ -376,8 +376,8 @@ static int mtk_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
|
||||
int len)
|
||||
static int mtk_nor_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
int ret;
|
||||
struct mtk_nor *mtk_nor = nor->priv;
|
||||
|
@ -419,6 +419,13 @@ static int mtk_nor_enable_clk(struct mtk_nor *mtk_nor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_nor_controller_ops mtk_controller_ops = {
|
||||
.read_reg = mtk_nor_read_reg,
|
||||
.write_reg = mtk_nor_write_reg,
|
||||
.read = mtk_nor_read,
|
||||
.write = mtk_nor_write,
|
||||
};
|
||||
|
||||
static int mtk_nor_init(struct mtk_nor *mtk_nor,
|
||||
struct device_node *flash_node)
|
||||
{
|
||||
|
@ -438,12 +445,8 @@ static int mtk_nor_init(struct mtk_nor *mtk_nor,
|
|||
nor->dev = mtk_nor->dev;
|
||||
nor->priv = mtk_nor;
|
||||
spi_nor_set_flash_node(nor, flash_node);
|
||||
nor->controller_ops = &mtk_controller_ops;
|
||||
|
||||
/* fill the hooks to spi nor */
|
||||
nor->read = mtk_nor_read;
|
||||
nor->read_reg = mtk_nor_read_reg;
|
||||
nor->write = mtk_nor_write;
|
||||
nor->write_reg = mtk_nor_write_reg;
|
||||
nor->mtd.name = "mtk_nor";
|
||||
/* initialized with NULL */
|
||||
ret = spi_nor_scan(nor, NULL, &hwcaps);
|
||||
|
|
|
@ -123,7 +123,8 @@ static int nxp_spifi_set_memory_mode_on(struct nxp_spifi *spifi)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int nxp_spifi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
||||
static int nxp_spifi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct nxp_spifi *spifi = nor->priv;
|
||||
u32 cmd;
|
||||
|
@ -145,7 +146,8 @@ static int nxp_spifi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
|||
return nxp_spifi_wait_for_cmd(spifi);
|
||||
}
|
||||
|
||||
static int nxp_spifi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
|
||||
static int nxp_spifi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct nxp_spifi *spifi = nor->priv;
|
||||
u32 cmd;
|
||||
|
@ -263,9 +265,18 @@ static int nxp_spifi_setup_memory_cmd(struct nxp_spifi *spifi)
|
|||
static void nxp_spifi_dummy_id_read(struct spi_nor *nor)
|
||||
{
|
||||
u8 id[SPI_NOR_MAX_ID_LEN];
|
||||
nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
|
||||
nor->controller_ops->read_reg(nor, SPINOR_OP_RDID, id,
|
||||
SPI_NOR_MAX_ID_LEN);
|
||||
}
|
||||
|
||||
static const struct spi_nor_controller_ops nxp_spifi_controller_ops = {
|
||||
.read_reg = nxp_spifi_read_reg,
|
||||
.write_reg = nxp_spifi_write_reg,
|
||||
.read = nxp_spifi_read,
|
||||
.write = nxp_spifi_write,
|
||||
.erase = nxp_spifi_erase,
|
||||
};
|
||||
|
||||
static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
|
||||
struct device_node *np)
|
||||
{
|
||||
|
@ -332,11 +343,7 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
|
|||
spifi->nor.dev = spifi->dev;
|
||||
spi_nor_set_flash_node(&spifi->nor, np);
|
||||
spifi->nor.priv = spifi;
|
||||
spifi->nor.read = nxp_spifi_read;
|
||||
spifi->nor.write = nxp_spifi_write;
|
||||
spifi->nor.erase = nxp_spifi_erase;
|
||||
spifi->nor.read_reg = nxp_spifi_read_reg;
|
||||
spifi->nor.write_reg = nxp_spifi_write_reg;
|
||||
spifi->nor.controller_ops = &nxp_spifi_controller_ops;
|
||||
|
||||
/*
|
||||
* The first read on a hard reset isn't reliable so do a
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -509,11 +509,9 @@ static const struct file_operations eraseblk_count_fops = {
|
|||
*/
|
||||
int ubi_debugfs_init_dev(struct ubi_device *ubi)
|
||||
{
|
||||
int err, n;
|
||||
unsigned long ubi_num = ubi->ubi_num;
|
||||
const char *fname;
|
||||
struct dentry *dent;
|
||||
struct ubi_debug_info *d = &ubi->dbg;
|
||||
int n;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_DEBUG_FS))
|
||||
return 0;
|
||||
|
@ -522,95 +520,52 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
|
|||
ubi->ubi_num);
|
||||
if (n == UBI_DFS_DIR_LEN) {
|
||||
/* The array size is too small */
|
||||
fname = UBI_DFS_DIR_NAME;
|
||||
dent = ERR_PTR(-EINVAL);
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fname = d->dfs_dir_name;
|
||||
dent = debugfs_create_dir(fname, dfs_rootdir);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
goto out;
|
||||
d->dfs_dir = dent;
|
||||
d->dfs_dir = debugfs_create_dir(d->dfs_dir_name, dfs_rootdir);
|
||||
|
||||
fname = "chk_gen";
|
||||
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||
&dfs_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
goto out_remove;
|
||||
d->dfs_chk_gen = dent;
|
||||
d->dfs_chk_gen = debugfs_create_file("chk_gen", S_IWUSR, d->dfs_dir,
|
||||
(void *)ubi_num, &dfs_fops);
|
||||
|
||||
fname = "chk_io";
|
||||
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||
&dfs_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
goto out_remove;
|
||||
d->dfs_chk_io = dent;
|
||||
d->dfs_chk_io = debugfs_create_file("chk_io", S_IWUSR, d->dfs_dir,
|
||||
(void *)ubi_num, &dfs_fops);
|
||||
|
||||
fname = "chk_fastmap";
|
||||
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||
&dfs_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
goto out_remove;
|
||||
d->dfs_chk_fastmap = dent;
|
||||
d->dfs_chk_fastmap = debugfs_create_file("chk_fastmap", S_IWUSR,
|
||||
d->dfs_dir, (void *)ubi_num,
|
||||
&dfs_fops);
|
||||
|
||||
fname = "tst_disable_bgt";
|
||||
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||
&dfs_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
goto out_remove;
|
||||
d->dfs_disable_bgt = dent;
|
||||
d->dfs_disable_bgt = debugfs_create_file("tst_disable_bgt", S_IWUSR,
|
||||
d->dfs_dir, (void *)ubi_num,
|
||||
&dfs_fops);
|
||||
|
||||
fname = "tst_emulate_bitflips";
|
||||
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||
&dfs_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
goto out_remove;
|
||||
d->dfs_emulate_bitflips = dent;
|
||||
d->dfs_emulate_bitflips = debugfs_create_file("tst_emulate_bitflips",
|
||||
S_IWUSR, d->dfs_dir,
|
||||
(void *)ubi_num,
|
||||
&dfs_fops);
|
||||
|
||||
fname = "tst_emulate_io_failures";
|
||||
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||
&dfs_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
goto out_remove;
|
||||
d->dfs_emulate_io_failures = dent;
|
||||
d->dfs_emulate_io_failures = debugfs_create_file("tst_emulate_io_failures",
|
||||
S_IWUSR, d->dfs_dir,
|
||||
(void *)ubi_num,
|
||||
&dfs_fops);
|
||||
|
||||
fname = "tst_emulate_power_cut";
|
||||
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||
&dfs_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
goto out_remove;
|
||||
d->dfs_emulate_power_cut = dent;
|
||||
d->dfs_emulate_power_cut = debugfs_create_file("tst_emulate_power_cut",
|
||||
S_IWUSR, d->dfs_dir,
|
||||
(void *)ubi_num,
|
||||
&dfs_fops);
|
||||
|
||||
fname = "tst_emulate_power_cut_min";
|
||||
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||
&dfs_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
goto out_remove;
|
||||
d->dfs_power_cut_min = dent;
|
||||
d->dfs_power_cut_min = debugfs_create_file("tst_emulate_power_cut_min",
|
||||
S_IWUSR, d->dfs_dir,
|
||||
(void *)ubi_num, &dfs_fops);
|
||||
|
||||
fname = "tst_emulate_power_cut_max";
|
||||
dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
||||
&dfs_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
goto out_remove;
|
||||
d->dfs_power_cut_max = dent;
|
||||
d->dfs_power_cut_max = debugfs_create_file("tst_emulate_power_cut_max",
|
||||
S_IWUSR, d->dfs_dir,
|
||||
(void *)ubi_num, &dfs_fops);
|
||||
|
||||
fname = "detailed_erase_block_info";
|
||||
dent = debugfs_create_file(fname, S_IRUSR, d->dfs_dir, (void *)ubi_num,
|
||||
&eraseblk_count_fops);
|
||||
if (IS_ERR_OR_NULL(dent))
|
||||
goto out_remove;
|
||||
debugfs_create_file("detailed_erase_block_info", S_IRUSR, d->dfs_dir,
|
||||
(void *)ubi_num, &eraseblk_count_fops);
|
||||
|
||||
return 0;
|
||||
|
||||
out_remove:
|
||||
debugfs_remove_recursive(d->dfs_dir);
|
||||
out:
|
||||
err = dent ? PTR_ERR(dent) : -ENODEV;
|
||||
ubi_err(ubi, "cannot create \"%s\" debugfs file or directory, error %d\n",
|
||||
fname, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#define SNOR_MFR_INTEL CFI_MFR_INTEL
|
||||
#define SNOR_MFR_ST CFI_MFR_ST /* ST Micro */
|
||||
#define SNOR_MFR_MICRON CFI_MFR_MICRON /* Micron */
|
||||
#define SNOR_MFR_ISSI CFI_MFR_PMC
|
||||
#define SNOR_MFR_MACRONIX CFI_MFR_MACRONIX
|
||||
#define SNOR_MFR_SPANSION CFI_MFR_AMD
|
||||
#define SNOR_MFR_SST CFI_MFR_SST
|
||||
|
@ -133,7 +134,7 @@
|
|||
#define SR_E_ERR BIT(5)
|
||||
#define SR_P_ERR BIT(6)
|
||||
|
||||
#define SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */
|
||||
#define SR1_QUAD_EN_BIT6 BIT(6)
|
||||
|
||||
/* Enhanced Volatile Configuration Register bits */
|
||||
#define EVCR_QUAD_EN_MICRON BIT(7) /* Micron Quad I/O */
|
||||
|
@ -144,10 +145,8 @@
|
|||
#define FSR_P_ERR BIT(4) /* Program operation status */
|
||||
#define FSR_PT_ERR BIT(1) /* Protection error bit */
|
||||
|
||||
/* Configuration Register bits. */
|
||||
#define CR_QUAD_EN_SPAN BIT(1) /* Spansion Quad I/O */
|
||||
|
||||
/* Status Register 2 bits. */
|
||||
#define SR2_QUAD_EN_BIT1 BIT(1)
|
||||
#define SR2_QUAD_EN_BIT7 BIT(7)
|
||||
|
||||
/* Supported SPI protocols */
|
||||
|
@ -243,6 +242,9 @@ enum spi_nor_option_flags {
|
|||
SNOR_F_4B_OPCODES = BIT(6),
|
||||
SNOR_F_HAS_4BAIT = BIT(7),
|
||||
SNOR_F_HAS_LOCK = BIT(8),
|
||||
SNOR_F_HAS_16BIT_SR = BIT(9),
|
||||
SNOR_F_NO_READ_CR = BIT(10),
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -465,6 +467,34 @@ enum spi_nor_pp_command_index {
|
|||
/* Forward declaration that will be used in 'struct spi_nor_flash_parameter' */
|
||||
struct spi_nor;
|
||||
|
||||
/**
|
||||
* struct spi_nor_controller_ops - SPI NOR controller driver specific
|
||||
* operations.
|
||||
* @prepare: [OPTIONAL] do some preparations for the
|
||||
* read/write/erase/lock/unlock operations.
|
||||
* @unprepare: [OPTIONAL] do some post work after the
|
||||
* read/write/erase/lock/unlock operations.
|
||||
* @read_reg: read out the register.
|
||||
* @write_reg: write data to the register.
|
||||
* @read: read data from the SPI NOR.
|
||||
* @write: write data to the SPI NOR.
|
||||
* @erase: erase a sector of the SPI NOR at the offset @offs; if
|
||||
* not provided by the driver, spi-nor will send the erase
|
||||
* opcode via write_reg().
|
||||
*/
|
||||
struct spi_nor_controller_ops {
|
||||
int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
|
||||
void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
|
||||
int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, size_t len);
|
||||
int (*write_reg)(struct spi_nor *nor, u8 opcode, const u8 *buf,
|
||||
size_t len);
|
||||
|
||||
ssize_t (*read)(struct spi_nor *nor, loff_t from, size_t len, u8 *buf);
|
||||
ssize_t (*write)(struct spi_nor *nor, loff_t to, size_t len,
|
||||
const u8 *buf);
|
||||
int (*erase)(struct spi_nor *nor, loff_t offs);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spi_nor_locking_ops - SPI NOR locking methods
|
||||
* @lock: lock a region of the SPI NOR.
|
||||
|
@ -549,19 +579,7 @@ struct flash_info;
|
|||
* @read_proto: the SPI protocol for read operations
|
||||
* @write_proto: the SPI protocol for write operations
|
||||
* @reg_proto the SPI protocol for read_reg/write_reg/erase operations
|
||||
* @prepare: [OPTIONAL] do some preparations for the
|
||||
* read/write/erase/lock/unlock operations
|
||||
* @unprepare: [OPTIONAL] do some post work after the
|
||||
* read/write/erase/lock/unlock operations
|
||||
* @read_reg: [DRIVER-SPECIFIC] read out the register
|
||||
* @write_reg: [DRIVER-SPECIFIC] write data to the register
|
||||
* @read: [DRIVER-SPECIFIC] read data from the SPI NOR
|
||||
* @write: [DRIVER-SPECIFIC] write data to the SPI NOR
|
||||
* @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR
|
||||
* at the offset @offs; if not provided by the driver,
|
||||
* spi-nor will send the erase opcode via write_reg()
|
||||
* @clear_sr_bp: [FLASH-SPECIFIC] clears the Block Protection Bits from
|
||||
* the SPI NOR Status Register.
|
||||
* @controller_ops: SPI NOR controller driver specific operations.
|
||||
* @params: [FLASH-SPECIFIC] SPI-NOR flash parameters and settings.
|
||||
* The structure includes legacy flash parameters and
|
||||
* settings that can be overwritten by the spi_nor_fixups
|
||||
|
@ -588,18 +606,8 @@ struct spi_nor {
|
|||
bool sst_write_second;
|
||||
u32 flags;
|
||||
|
||||
int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
|
||||
void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
|
||||
int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
|
||||
int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
|
||||
const struct spi_nor_controller_ops *controller_ops;
|
||||
|
||||
ssize_t (*read)(struct spi_nor *nor, loff_t from,
|
||||
size_t len, u_char *read_buf);
|
||||
ssize_t (*write)(struct spi_nor *nor, loff_t to,
|
||||
size_t len, const u_char *write_buf);
|
||||
int (*erase)(struct spi_nor *nor, loff_t offs);
|
||||
|
||||
int (*clear_sr_bp)(struct spi_nor *nor);
|
||||
struct spi_nor_flash_parameter params;
|
||||
|
||||
void *priv;
|
||||
|
|
|
@ -13,6 +13,7 @@ enum intel_spi_type {
|
|||
INTEL_SPI_BYT = 1,
|
||||
INTEL_SPI_LPT,
|
||||
INTEL_SPI_BXT,
|
||||
INTEL_SPI_CNL,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue