Commit ce1bf979 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-20170212' of git://git.infradead.org/linux-mtd

Pull MTD updates from Brian Norris:
 "MTD updates for 4.11:

  General:
   - new kernel API for retrieving max bad blocks per die (not used yet)
   - track (and expose via sysfs) a partition's device tree node
   - support a "label" device tree property for naming an MTD

  NAND:
   - sunxi: avoid busy-waiting for NAND events
   - ifc: fix ECC handling on IFC v1.0
   - OX820: add explicit dependency on ARCH_OXNAS in Kconfig
   - core: add a new manufacture ID and fix a kernel-doc warning
   - fsmc: kill pdata support
   - lpc32xx_slc: remove unneeded NULL check
   - support dynamic "max bad blocks" detection via ONFI

  SPI NOR:
   - add support for the 4-byte address instruction set
   - add support for new memory parts
   - add support to S3AN memories
   - add support to the Intel SPI controller
   - add support to the Aspeed AST2400 and AST2550 controllers
   - support max SPI message sizes in m25p80_read()
   - fixes for the Candence and Freescale QSPI drivers

  Other:
   - add support for Gemini flash probing
   - bcm47xxsflash: add support for reading outside memory-mapped window
   - bcm47xxparts: extend to support multiple TRX partitions
   - misc fixes and typos

  Extra note: we've pulled in an MFD subtree from Lee Jones as a
  dependency for a new Intel SPI NOR driver"

[ Kudos to Brian for sending pull request a week early:

   "I refuse to acknowledge the existence of 4.10-rc8 and am therefore
    sending our MTD changes for 4.11 now"

  which is all good ]

* tag 'for-linus-20170212' of git://git.infradead.org/linux-mtd: (52 commits)
  mtd: aspeed: remove redundant dev_err call in aspeed_smc_probe()
  dt-bindings: mtd: add a common label property to all mtd devices
  mtd: name the mtd device with an optional label property
  mtd: physmap_of: fixup gemini/versatile dependencies
  mtd: spi-nor: cqspi: remove redundant dead code on error return check
  Documentation: mtk-quadspi: update DT bindings
  mtd: fsl-quadspi: Rename SEQID_QUAD_READ to SEQID_READ
  mtd:fsl-quadspi:use the property fields of SPI-NOR
  mtd: spi-nor: Add support for gd25q16
  mtd: spi-nor: Fix S3AN addressing calculation
  mtd: aspeed: fix compile warning in aspeed_smc_read_from_ahb()
  mtd: spi-nor: add dt support for Everspin MRAMs
  mtd: spi-nor: Add lock/unlock support for f25l32pa
  mtd: spi-nor: add a stateless method to support memory size above 128Mib
  mtd: spi-nor: rename SPINOR_OP_* macros of the 4-byte address op codes
  mtd: m25p80: consider max message size in m25p80_read
  mtd: spi-nor: bindings for the Aspeed memory controllers
  mtd: aspeed: add memory controllers for the Aspeed AST2400 SoC
  mtd: spi-nor: add memory controllers for the Aspeed AST2500 SoC
  mtd: spi-nor: remove WARN_ONCE() message in spi_nor_write()
  ...
parents c470abd4 d91f6cee
* Aspeed Firmware Memory controller
* Aspeed SPI Flash Memory Controller
The Firmware Memory Controller in the Aspeed AST2500 SoC supports
three chip selects, two of which are always of SPI type and the third
can be SPI or NOR type flash. These bindings only describe SPI.
The two SPI flash memory controllers in the AST2500 each support two
chip selects.
Required properties:
- compatible : Should be one of
"aspeed,ast2400-fmc" for the AST2400 Firmware Memory Controller
"aspeed,ast2400-spi" for the AST2400 SPI Flash memory Controller
"aspeed,ast2500-fmc" for the AST2500 Firmware Memory Controller
"aspeed,ast2500-spi" for the AST2500 SPI flash memory controllers
- reg : the first contains the control register location and length,
the second contains the memory window mapping address and length
- #address-cells : must be 1 corresponding to chip select child binding
- #size-cells : must be 0 corresponding to chip select child binding
Optional properties:
- interrupts : Should contain the interrupt for the dma device if an
FMC
The child nodes are the SPI flash modules which must have a compatible
property as specified in bindings/mtd/jedec,spi-nor.txt
Optionally, the child node can contain properties for SPI mode (may be
ignored):
- spi-max-frequency - max frequency of spi bus
Example:
fmc: fmc@1e620000 {
compatible = "aspeed,ast2500-fmc";
reg = < 0x1e620000 0x94
0x20000000 0x02000000 >;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <19>;
flash@0 {
reg = < 0 >;
compatible = "jedec,spi-nor";
/* spi-max-frequency = <>; */
/* m25p,fast-read; */
#address-cells = <1>;
#size-cells = <1>;
};
};
* Common properties of all MTD devices
Optional properties:
- label: user-defined MTD device name. Can be used to assign user
friendly names to MTD devices (instead of the flash model or flash
controller based name) in order to ease flash device identification
and/or describe what they are used for.
Example:
flash@0 {
label = "System-firmware";
/* flash type specific properties */
};
Flash device on Cortina Systems Gemini SoC
This flash is regular CFI compatible (Intel or AMD extended) flash chips with
some special bits that can be controlled by the machine's system controller.
Required properties:
- compatible : must be "cortina,gemini-flash", "cfi-flash";
- reg : memory address for the flash chip
- syscon : must be a phandle to the system controller
- 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@30000000 {
compatible = "cortina,gemini-flash", "cfi-flash";
reg = <0x30000000 0x01000000>;
syscon = <&syscon>;
bank-width = <2>;
};
...@@ -14,6 +14,8 @@ Required properties: ...@@ -14,6 +14,8 @@ Required properties:
at25df641 at25df641
at26df081a at26df081a
mr25h256 mr25h256
mr25h10
mr25h40
mx25l4005a mx25l4005a
mx25l1606e mx25l1606e
mx25l6405d mx25l6405d
......
* Serial NOR flash controller for MTK MT81xx (and similar) * Serial NOR flash controller for MTK MT81xx (and similar)
Required properties: Required properties:
- compatible: should be "mediatek,mt8173-nor"; - compatible: The possible values are:
"mediatek,mt2701-nor"
"mediatek,mt7623-nor"
"mediatek,mt8173-nor"
For mt8173, compatible should be "mediatek,mt8173-nor".
For every other SoC, should contain both the SoC-specific compatible string
and "mediatek,mt8173-nor".
- reg: physical base address and length of the controller's register - reg: physical base address and length of the controller's register
- clocks: the phandle of the clocks needed by the nor controller - clocks: the phandle of the clocks needed by the nor controller
- clock-names: the names of the clocks - clock-names: the names of the clocks
......
Upgrading BIOS using intel-spi
------------------------------
Many Intel CPUs like Baytrail and Braswell include SPI serial flash host
controller which is used to hold BIOS and other platform specific data.
Since contents of the SPI serial flash is crucial for machine to function,
it is typically protected by different hardware protection mechanisms to
avoid accidental (or on purpose) overwrite of the content.
Not all manufacturers protect the SPI serial flash, mainly because it
allows upgrading the BIOS image directly from an OS.
The intel-spi driver makes it possible to read and write the SPI serial
flash, if certain protection bits are not set and locked. If it finds
any of them set, the whole MTD device is made read-only to prevent
partial overwrites. By default the driver exposes SPI serial flash
contents as read-only but it can be changed from kernel command line,
passing "intel-spi.writeable=1".
Please keep in mind that overwriting the BIOS image on SPI serial flash
might render the machine unbootable and requires special equipment like
Dediprog to revive. You have been warned!
Below are the steps how to upgrade MinnowBoard MAX BIOS directly from
Linux.
1) Download and extract the latest Minnowboard MAX BIOS SPI image
[1]. At the time writing this the latest image is v92.
2) Install mtd-utils package [2]. We need this in order to erase the SPI
serial flash. Distros like Debian and Fedora have this prepackaged with
name "mtd-utils".
3) Add "intel-spi.writeable=1" to the kernel command line and reboot
the board (you can also reload the driver passing "writeable=1" as
module parameter to modprobe).
4) Once the board is up and running again, find the right MTD partition
(it is named as "BIOS"):
# cat /proc/mtd
dev: size erasesize name
mtd0: 00800000 00001000 "BIOS"
So here it will be /dev/mtd0 but it may vary.
5) Make backup of the existing image first:
# dd if=/dev/mtd0ro of=bios.bak
16384+0 records in
16384+0 records out
8388608 bytes (8.4 MB) copied, 10.0269 s, 837 kB/s
6) Verify the backup
# sha1sum /dev/mtd0ro bios.bak
fdbb011920572ca6c991377c4b418a0502668b73 /dev/mtd0ro
fdbb011920572ca6c991377c4b418a0502668b73 bios.bak
The SHA1 sums must match. Otherwise do not continue any further!
7) Erase the SPI serial flash. After this step, do not reboot the
board! Otherwise it will not start anymore.
# flash_erase /dev/mtd0 0 0
Erasing 4 Kibyte @ 7ff000 -- 100 % complete
8) Once completed without errors you can write the new BIOS image:
# dd if=MNW2MAX1.X64.0092.R01.1605221712.bin of=/dev/mtd0
9) Verify that the new content of the SPI serial flash matches the new
BIOS image:
# sha1sum /dev/mtd0ro MNW2MAX1.X64.0092.R01.1605221712.bin
9b4df9e4be2057fceec3a5529ec3d950836c87a2 /dev/mtd0ro
9b4df9e4be2057fceec3a5529ec3d950836c87a2 MNW2MAX1.X64.0092.R01.1605221712.bin
The SHA1 sums should match.
10) Now you can reboot your board and observe the new BIOS starting up
properly.
References
----------
[1] https://firmware.intel.com/sites/default/files/MinnowBoard.MAX_.X64.92.R01.zip
[2] http://www.linux-mtd.infradead.org/
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
* document number TBD : Wildcat Point-LP * document number TBD : Wildcat Point-LP
* document number TBD : 9 Series * document number TBD : 9 Series
* document number TBD : Lewisburg * document number TBD : Lewisburg
* document number TBD : Apollo Lake SoC
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
...@@ -83,6 +84,17 @@ ...@@ -83,6 +84,17 @@
#define ACPIBASE_GCS_OFF 0x3410 #define ACPIBASE_GCS_OFF 0x3410
#define ACPIBASE_GCS_END 0x3414 #define ACPIBASE_GCS_END 0x3414
#define SPIBASE_BYT 0x54
#define SPIBASE_BYT_SZ 512
#define SPIBASE_BYT_EN BIT(1)
#define SPIBASE_LPT 0x3800
#define SPIBASE_LPT_SZ 512
#define BCR 0xdc
#define BCR_WPD BIT(0)
#define SPIBASE_APL_SZ 4096
#define GPIOBASE_ICH0 0x58 #define GPIOBASE_ICH0 0x58
#define GPIOCTRL_ICH0 0x5C #define GPIOCTRL_ICH0 0x5C
#define GPIOBASE_ICH6 0x48 #define GPIOBASE_ICH6 0x48
...@@ -133,6 +145,12 @@ static struct resource gpio_ich_res[] = { ...@@ -133,6 +145,12 @@ static struct resource gpio_ich_res[] = {
}, },
}; };
static struct resource intel_spi_res[] = {
{
.flags = IORESOURCE_MEM,
}
};
static struct mfd_cell lpc_ich_wdt_cell = { static struct mfd_cell lpc_ich_wdt_cell = {
.name = "iTCO_wdt", .name = "iTCO_wdt",
.num_resources = ARRAY_SIZE(wdt_ich_res), .num_resources = ARRAY_SIZE(wdt_ich_res),
...@@ -147,6 +165,14 @@ static struct mfd_cell lpc_ich_gpio_cell = { ...@@ -147,6 +165,14 @@ static struct mfd_cell lpc_ich_gpio_cell = {
.ignore_resource_conflicts = true, .ignore_resource_conflicts = true,
}; };
static struct mfd_cell lpc_ich_spi_cell = {
.name = "intel-spi",
.num_resources = ARRAY_SIZE(intel_spi_res),
.resources = intel_spi_res,
.ignore_resource_conflicts = true,
};
/* chipset related info */ /* chipset related info */
enum lpc_chipsets { enum lpc_chipsets {
LPC_ICH = 0, /* ICH */ LPC_ICH = 0, /* ICH */
...@@ -216,6 +242,7 @@ enum lpc_chipsets { ...@@ -216,6 +242,7 @@ enum lpc_chipsets {
LPC_BRASWELL, /* Braswell SoC */ LPC_BRASWELL, /* Braswell SoC */
LPC_LEWISBURG, /* Lewisburg */ LPC_LEWISBURG, /* Lewisburg */
LPC_9S, /* 9 Series */ LPC_9S, /* 9 Series */
LPC_APL, /* Apollo Lake SoC */
}; };
static struct lpc_ich_info lpc_chipset_info[] = { static struct lpc_ich_info lpc_chipset_info[] = {
...@@ -494,10 +521,12 @@ static struct lpc_ich_info lpc_chipset_info[] = { ...@@ -494,10 +521,12 @@ static struct lpc_ich_info lpc_chipset_info[] = {
.name = "Lynx Point", .name = "Lynx Point",
.iTCO_version = 2, .iTCO_version = 2,
.gpio_version = ICH_V5_GPIO, .gpio_version = ICH_V5_GPIO,
.spi_type = INTEL_SPI_LPT,
}, },
[LPC_LPT_LP] = { [LPC_LPT_LP] = {
.name = "Lynx Point_LP", .name = "Lynx Point_LP",
.iTCO_version = 2, .iTCO_version = 2,
.spi_type = INTEL_SPI_LPT,
}, },
[LPC_WBG] = { [LPC_WBG] = {
.name = "Wellsburg", .name = "Wellsburg",
...@@ -511,6 +540,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { ...@@ -511,6 +540,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
[LPC_BAYTRAIL] = { [LPC_BAYTRAIL] = {
.name = "Bay Trail SoC", .name = "Bay Trail SoC",
.iTCO_version = 3, .iTCO_version = 3,
.spi_type = INTEL_SPI_BYT,
}, },
[LPC_COLETO] = { [LPC_COLETO] = {
.name = "Coleto Creek", .name = "Coleto Creek",
...@@ -519,10 +549,12 @@ static struct lpc_ich_info lpc_chipset_info[] = { ...@@ -519,10 +549,12 @@ static struct lpc_ich_info lpc_chipset_info[] = {
[LPC_WPT_LP] = { [LPC_WPT_LP] = {
.name = "Wildcat Point_LP", .name = "Wildcat Point_LP",
.iTCO_version = 2, .iTCO_version = 2,
.spi_type = INTEL_SPI_LPT,
}, },
[LPC_BRASWELL] = { [LPC_BRASWELL] = {
.name = "Braswell SoC", .name = "Braswell SoC",
.iTCO_version = 3, .iTCO_version = 3,
.spi_type = INTEL_SPI_BYT,
}, },
[LPC_LEWISBURG] = { [LPC_LEWISBURG] = {
.name = "Lewisburg", .name = "Lewisburg",
...@@ -533,6 +565,10 @@ static struct lpc_ich_info lpc_chipset_info[] = { ...@@ -533,6 +565,10 @@ static struct lpc_ich_info lpc_chipset_info[] = {
.iTCO_version = 2, .iTCO_version = 2,
.gpio_version = ICH_V5_GPIO, .gpio_version = ICH_V5_GPIO,
}, },
[LPC_APL] = {
.name = "Apollo Lake SoC",
.spi_type = INTEL_SPI_BXT,
},
}; };
/* /*
...@@ -681,6 +717,7 @@ static const struct pci_device_id lpc_ich_ids[] = { ...@@ -681,6 +717,7 @@ static const struct pci_device_id lpc_ich_ids[] = {
{ PCI_VDEVICE(INTEL, 0x3b14), LPC_3420}, { PCI_VDEVICE(INTEL, 0x3b14), LPC_3420},
{ PCI_VDEVICE(INTEL, 0x3b16), LPC_3450}, { PCI_VDEVICE(INTEL, 0x3b16), LPC_3450},
{ PCI_VDEVICE(INTEL, 0x5031), LPC_EP80579}, { PCI_VDEVICE(INTEL, 0x5031), LPC_EP80579},
{ PCI_VDEVICE(INTEL, 0x5ae8), LPC_APL},
{ PCI_VDEVICE(INTEL, 0x8c40), LPC_LPT}, { PCI_VDEVICE(INTEL, 0x8c40), LPC_LPT},
{ PCI_VDEVICE(INTEL, 0x8c41), LPC_LPT}, { PCI_VDEVICE(INTEL, 0x8c41), LPC_LPT},
{ PCI_VDEVICE(INTEL, 0x8c42), LPC_LPT}, { PCI_VDEVICE(INTEL, 0x8c42), LPC_LPT},
...@@ -1056,6 +1093,94 @@ static int lpc_ich_init_wdt(struct pci_dev *dev) ...@@ -1056,6 +1093,94 @@ static int lpc_ich_init_wdt(struct pci_dev *dev)
return ret; return ret;
} }
static int lpc_ich_init_spi(struct pci_dev *dev)
{
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
struct resource *res = &intel_spi_res[0];
struct intel_spi_boardinfo *info;
u32 spi_base, rcba, bcr;
info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->type = lpc_chipset_info[priv->chipset].spi_type;
switch (info->type) {
case INTEL_SPI_BYT:
pci_read_config_dword(dev, SPIBASE_BYT, &spi_base);
if (spi_base & SPIBASE_BYT_EN) {
res->start = spi_base & ~(SPIBASE_BYT_SZ - 1);
res->end = res->start + SPIBASE_BYT_SZ - 1;
}
break;
case INTEL_SPI_LPT:
pci_read_config_dword(dev, RCBABASE, &rcba);
if (rcba & 1) {
spi_base = round_down(rcba, SPIBASE_LPT_SZ);
res->start = spi_base + SPIBASE_LPT;
res->end = res->start + SPIBASE_LPT_SZ - 1;
/*
* Try to make the flash chip writeable now by
* setting BCR_WPD. It it fails we tell the driver
* that it can only read the chip.
*/
pci_read_config_dword(dev, BCR, &bcr);
if (!(bcr & BCR_WPD)) {
bcr |= BCR_WPD;
pci_write_config_dword(dev, BCR, bcr);
pci_read_config_dword(dev, BCR, &bcr);
}
info->writeable = !!(bcr & BCR_WPD);
}
break;
case INTEL_SPI_BXT: {
unsigned int p2sb = PCI_DEVFN(13, 0);
unsigned int spi = PCI_DEVFN(13, 2);
struct pci_bus *bus = dev->bus;
/*
* The P2SB is hidden by BIOS and we need to unhide it in
* order to read BAR of the SPI flash device. Once that is
* done we hide it again.
*/
pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x0);
pci_bus_read_config_dword(bus, spi, PCI_BASE_ADDRESS_0,
&spi_base);
if (spi_base != ~0) {
res->start = spi_base & 0xfffffff0;
res->end = res->start + SPIBASE_APL_SZ - 1;
pci_bus_read_config_dword(bus, spi, BCR, &bcr);
if (!(bcr & BCR_WPD)) {
bcr |= BCR_WPD;
pci_bus_write_config_dword(bus, spi, BCR, bcr);
pci_bus_read_config_dword(bus, spi, BCR, &bcr);
}
info->writeable = !!(bcr & BCR_WPD);
}
pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x1);
break;
}
default:
return -EINVAL;
}
if (!res->start)
return -ENODEV;
lpc_ich_spi_cell.platform_data = info;
lpc_ich_spi_cell.pdata_size = sizeof(*info);
return mfd_add_devices(&dev->dev, PLATFORM_DEVID_NONE,
&lpc_ich_spi_cell, 1, NULL, 0, NULL);
}
static int lpc_ich_probe(struct pci_dev *dev, static int lpc_ich_probe(struct pci_dev *dev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
...@@ -1099,6 +1224,12 @@ static int lpc_ich_probe(struct pci_dev *dev, ...@@ -1099,6 +1224,12 @@ static int lpc_ich_probe(struct pci_dev *dev,
cell_added = true; cell_added = true;
} }
if (lpc_chipset_info[priv->chipset].spi_type) {
ret = lpc_ich_init_spi(dev);
if (!ret)
cell_added = true;
}
/* /*
* We only care if at least one or none of the cells registered * We only care if at least one or none of the cells registered
* successfully. * successfully.
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* *
*/ */
#include <linux/bcm47xx_nvram.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -83,6 +84,91 @@ static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master, ...@@ -83,6 +84,91 @@ static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
return "rootfs"; return "rootfs";
} }
static int bcm47xxpart_parse_trx(struct mtd_info *master,
struct mtd_partition *trx,
struct mtd_partition *parts,
size_t parts_len)
{
struct trx_header header;
size_t bytes_read;
int curr_part = 0;
int i, err;
if (parts_len < 3) {
pr_warn("No enough space to add TRX partitions!\n");
return -ENOMEM;
}
err = mtd_read(master, trx->offset, sizeof(header), &bytes_read,
(uint8_t *)&header);
if (err && !mtd_is_bitflip(err)) {
pr_err("mtd_read error while reading TRX header: %d\n", err);
return err;
}
i = 0;
/* We have LZMA loader if offset[2] points to sth */
if (header.offset[2]) {
bcm47xxpart_add_part(&parts[curr_part++], "loader",
trx->offset + header.offset[i], 0);
i++;
}
if (header.offset[i]) {
bcm47xxpart_add_part(&parts[curr_part++], "linux",
trx->offset + header.offset[i], 0);
i++;
}
if (header.offset[i]) {
size_t offset = trx->offset + header.offset[i];
const char *name = bcm47xxpart_trx_data_part_name(master,
offset);
bcm47xxpart_add_part(&parts[curr_part++], name, offset, 0);
i++;
}
/*
* Assume that every partition ends at the beginning of the one it is
* followed by.
*/
for (i = 0; i < curr_part; i++) {
u64 next_part_offset = (i < curr_part - 1) ?
parts[i + 1].offset :
trx->offset + trx->size;
parts[i].size = next_part_offset - parts[i].offset;
}
return curr_part;
}
/**
* bcm47xxpart_bootpartition - gets index of TRX partition used by bootloader
*
* Some devices may have more than one TRX partition. In such case one of them
* is the main one and another a failsafe one. Bootloader may fallback to the
* failsafe firmware if it detects corruption of the main image.
*
* This function provides info about currently used TRX partition. It's the one
* containing kernel started by the bootloader.
*/
static int bcm47xxpart_bootpartition(void)
{
char buf[4];
int bootpartition;
/* Check CFE environment variable */
if (bcm47xx_nvram_getenv("bootpartition", buf, sizeof(buf)) > 0) {
if (!kstrtoint(buf, 0, &bootpartition))
return bootpartition;
}
return 0;
}
static int bcm47xxpart_parse(struct mtd_info *master, static int bcm47xxpart_parse(struct mtd_info *master,
const struct mtd_partition **pparts, const struct mtd_partition **pparts,
struct mtd_part_parser_data *data) struct mtd_part_parser_data *data)
...@@ -93,9 +179,8 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -93,9 +179,8 @@ static int bcm47xxpart_parse(struct mtd_info *master,
size_t bytes_read; size_t bytes_read;
uint32_t offset; uint32_t offset;
uint32_t blocksize = master->erasesize; uint32_t blocksize = master->erasesize;
struct trx_header *trx; int trx_parts[2]; /* Array with indexes of TRX partitions */
int trx_part = -1; int trx_num = 0; /* Number of found TRX partitions */
int last_trx_part = -1;
int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, }; int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
int err; int err;
...@@ -182,54 +267,18 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -182,54 +267,18 @@ static int bcm47xxpart_parse(struct mtd_info *master,
/* TRX */ /* TRX */
if (buf[0x000 / 4] == TRX_MAGIC) { if (buf[0x000 / 4] == TRX_MAGIC) {
if (BCM47XXPART_MAX_PARTS - curr_part < 4) { struct trx_header *trx;
pr_warn("Not enough partitions left to register trx, scanning stopped!\n");
break;
}
trx = (struct trx_header *)buf;
trx_part = curr_part; if (trx_num >= ARRAY_SIZE(trx_parts))
pr_warn("No enough space to store another TRX found at 0x%X\n",
offset);
else
trx_parts[trx_num++] = curr_part;
bcm47xxpart_add_part(&parts[curr_part++], "firmware", bcm47xxpart_add_part(&parts[curr_part++], "firmware",
offset, 0); offset, 0);
i = 0;
/* We have LZMA loader if offset[2] points to sth */
if (trx->offset[2]) {
bcm47xxpart_add_part(&parts[curr_part++],
"loader",
offset + trx->offset[i],
0);
i++;
}
if (trx->offset[i]) {
bcm47xxpart_add_part(&parts[curr_part++],
"linux",
offset + trx->offset[i],
0);
i++;
}
/*
* Pure rootfs size is known and can be calculated as:
* trx->length - trx->offset[i]. We don't fill it as
* we want to have jffs2 (overlay) in the same mtd.
*/
if (trx->offset[i]) {
const char *name;
name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
bcm47xxpart_add_part(&parts[curr_part++],
name,
offset + trx->offset[i],
0);
i++;
}
last_trx_part = curr_part - 1;
/* Jump to the end of TRX */ /* Jump to the end of TRX */
trx = (struct trx_header *)buf;
offset = roundup(offset + trx->length, blocksize); offset = roundup(offset + trx->length, blocksize);
/* Next loop iteration will increase the offset */ /* Next loop iteration will increase the offset */
offset -= blocksize; offset -= blocksize;
...@@ -307,9 +356,23 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -307,9 +356,23 @@ static int bcm47xxpart_parse(struct mtd_info *master,
parts[i + 1].offset : master->size; parts[i + 1].offset : master->size;
parts[i].size = next_part_offset - parts[i].offset; parts[i].size = next_part_offset - parts[i].offset;
if (i == last_trx_part && trx_part >= 0) }
parts[trx_part].size = next_part_offset -
parts[trx_part].offset; /* If there was TRX parse it now */
for (i = 0; i < trx_num; i++) {
struct mtd_partition *trx = &parts[trx_parts[i]];
if (i == bcm47xxpart_bootpartition()) {
int num_parts;
num_parts = bcm47xxpart_parse_trx(master, trx,
parts + curr_part,
BCM47XXPART_MAX_PARTS - curr_part);
if (num_parts > 0)
curr_part += num_parts;
} else {
trx->name = "failsafe";
}
} }
*pparts = parts; *pparts = parts;
......
...@@ -105,15 +105,33 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -105,15 +105,33 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf) size_t *retlen, u_char *buf)
{ {
struct bcm47xxsflash *b47s = mtd->priv; struct bcm47xxsflash *b47s = mtd->priv;
size_t orig_len = len;
/* Check address range */ /* Check address range */
if ((from + len) > mtd->size) if ((from + len) > mtd->size)
return -EINVAL; return -EINVAL;
memcpy_fromio(buf, b47s->window + from, len); /* Read as much as possible using fast MMIO window */
*retlen = len; if (from < BCM47XXSFLASH_WINDOW_SZ) {
size_t memcpy_len;
return len; memcpy_len = min(len, (size_t)(BCM47XXSFLASH_WINDOW_SZ - from));
memcpy_fromio(buf, b47s->window + from, memcpy_len);
from += memcpy_len;
len -= memcpy_len;
buf += memcpy_len;
}
/* Use indirect access for content out of the window */
for (; len; len--) {
b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++);
bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B);
*buf++ = b47s->cc_read(b47s, BCMA_CC_FLASHDATA);
}
*retlen = orig_len;
return orig_len;
} }
static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len, static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len,
...@@ -284,7 +302,6 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) ...@@ -284,7 +302,6 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
b47s = devm_kzalloc(dev, sizeof(*b47s), GFP_KERNEL); b47s = devm_kzalloc(dev, sizeof(*b47s), GFP_KERNEL);
if (!b47s) if (!b47s)
return -ENOMEM; return -ENOMEM;
sflash->priv = b47s;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { if (!res) {
...@@ -334,6 +351,8 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) ...@@ -334,6 +351,8 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
b47s->size = sflash->size; b47s->size = sflash->size;
bcm47xxsflash_fill_mtd(b47s, &pdev->dev); bcm47xxsflash_fill_mtd(b47s, &pdev->dev);
platform_set_drvdata(pdev, b47s);
err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0); err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
if (err) { if (err) {
pr_err("Failed to register MTD device: %d\n", err); pr_err("Failed to register MTD device: %d\n", err);
...@@ -349,8 +368,7 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) ...@@ -349,8 +368,7 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
static int bcm47xxsflash_bcma_remove(struct platform_device *pdev) static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
{ {
struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); struct bcm47xxsflash *b47s = platform_get_drvdata(pdev);
struct bcm47xxsflash *b47s = sflash->priv;
mtd_device_unregister(&b47s->mtd); mtd_device_unregister(&b47s->mtd);
iounmap(b47s->window); iounmap(b47s->window);
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#define BCM47XXSFLASH_WINDOW_SZ SZ_16M
/* Used for ST flashes only. */ /* Used for ST flashes only. */
#define OPCODE_ST_WREN 0x0006 /* Write Enable */ #define OPCODE_ST_WREN 0x0006 /* Write Enable */
#define OPCODE_ST_WRDIS 0x0004 /* Write Disable */ #define OPCODE_ST_WRDIS 0x0004 /* Write Disable */
...@@ -16,6 +18,7 @@ ...@@ -16,6 +18,7 @@
#define OPCODE_ST_RES 0x03ab /* Read Electronic Signature */ #define OPCODE_ST_RES 0x03ab /* Read Electronic Signature */
#define OPCODE_ST_CSA 0x1000 /* Keep chip select asserted */ #define OPCODE_ST_CSA 0x1000 /* Keep chip select asserted */
#define OPCODE_ST_SSE 0x0220 /* Sub-sector Erase */ #define OPCODE_ST_SSE 0x0220 /* Sub-sector Erase */
#define OPCODE_ST_READ4B 0x6313 /* Read Data Bytes in 4Byte addressing mode */
/* Used for Atmel flashes only. */ /* Used for Atmel flashes only. */
#define OPCODE_AT_READ 0x07e8 #define OPCODE_AT_READ 0x07e8
......
...@@ -172,7 +172,8 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len, ...@@ -172,7 +172,8 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
t[1].rx_buf = buf; t[1].rx_buf = buf;
t[1].rx_nbits = m25p80_rx_nbits(nor); t[1].rx_nbits = m25p80_rx_nbits(nor);
t[1].len = min(len, spi_max_transfer_size(spi)); t[1].len = min3(len, spi_max_transfer_size(spi),
spi_max_message_size(spi) - t[0].len);
spi_message_add_tail(&t[1], &m); spi_message_add_tail(&t[1], &m);
ret = spi_sync(spi, &m); ret = spi_sync(spi, &m);
...@@ -288,7 +289,6 @@ static const struct spi_device_id m25p_ids[] = { ...@@ -288,7 +289,6 @@ static const struct spi_device_id m25p_ids[] = {
* should be kept for backward compatibility. * should be kept for backward compatibility.
*/ */
{"at25df321a"}, {"at25df641"}, {"at26df081a"}, {"at25df321a"}, {"at25df641"}, {"at26df081a"},
{"mr25h256"},
{"mx25l4005a"}, {"mx25l1606e"}, {"mx25l6405d"}, {"mx25l12805d"}, {"mx25l4005a"}, {"mx25l1606e"}, {"mx25l6405d"}, {"mx25l12805d"},
{"mx25l25635e"},{"mx66l51235l"}, {"mx25l25635e"},{"mx66l51235l"},
{"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q512a"}, {"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q512a"},
...@@ -305,6 +305,11 @@ static const struct spi_device_id m25p_ids[] = { ...@@ -305,6 +305,11 @@ static const struct spi_device_id m25p_ids[] = {
{"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"},
{"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"},
/* Everspin MRAMs (non-JEDEC) */
{ "mr25h256" }, /* 256 Kib, 40 MHz */
{ "mr25h10" }, /* 1 Mib, 40 MHz */
{ "mr25h40" }, /* 4 Mib, 40 MHz */
{ }, { },
}; };
MODULE_DEVICE_TABLE(spi, m25p_ids); MODULE_DEVICE_TABLE(spi, m25p_ids);
......
...@@ -18,19 +18,12 @@ ...@@ -18,19 +18,12 @@
#define SPINOR_OP_RDVCR 0x85 #define SPINOR_OP_RDVCR 0x85
/* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */ /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */
#define SPINOR_OP_READ_1_2_2 0xbb /* DUAL I/O READ */
#define SPINOR_OP_READ_1_4_4 0xeb /* QUAD I/O READ */
#define SPINOR_OP_WRITE 0x02 /* PAGE PROGRAM */ #define SPINOR_OP_WRITE 0x02 /* PAGE PROGRAM */
#define SPINOR_OP_WRITE_1_1_2 0xa2 /* DUAL INPUT PROGRAM */ #define SPINOR_OP_WRITE_1_1_2 0xa2 /* DUAL INPUT PROGRAM */
#define SPINOR_OP_WRITE_1_2_2 0xd2 /* DUAL INPUT EXT PROGRAM */ #define SPINOR_OP_WRITE_1_2_2 0xd2 /* DUAL INPUT EXT PROGRAM */
#define SPINOR_OP_WRITE_1_1_4 0x32 /* QUAD INPUT PROGRAM */ #define SPINOR_OP_WRITE_1_1_4 0x32 /* QUAD INPUT PROGRAM */
#define SPINOR_OP_WRITE_1_4_4 0x12 /* QUAD INPUT EXT PROGRAM */ #define SPINOR_OP_WRITE_1_4_4 0x12 /* QUAD INPUT EXT PROGRAM */
/* READ commands with 32-bit addressing */
#define SPINOR_OP_READ4_1_2_2 0xbc
#define SPINOR_OP_READ4_1_4_4 0xec
/* Configuration flags */ /* Configuration flags */
#define FLASH_FLAG_SINGLE 0x000000ff #define FLASH_FLAG_SINGLE 0x000000ff
#define FLASH_FLAG_READ_WRITE 0x00000001 #define FLASH_FLAG_READ_WRITE 0x00000001
......
...@@ -507,12 +507,12 @@ static struct seq_rw_config n25q_read3_configs[] = { ...@@ -507,12 +507,12 @@ static struct seq_rw_config n25q_read3_configs[] = {
* - 'FAST' variants configured for 8 dummy cycles (see note above.) * - 'FAST' variants configured for 8 dummy cycles (see note above.)
*/ */
static struct seq_rw_config n25q_read4_configs[] = { static struct seq_rw_config n25q_read4_configs[] = {
{FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4, 0, 4, 4, 0x00, 0, 8}, {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 0, 8},
{FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4, 0, 1, 4, 0x00, 0, 8}, {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8},
{FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2, 0, 2, 2, 0x00, 0, 8}, {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 0, 8},
{FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2, 0, 1, 2, 0x00, 0, 8}, {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8},
{FLASH_FLAG_READ_FAST, SPINOR_OP_READ4_FAST, 0, 1, 1, 0x00, 0, 8}, {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST_4B, 0, 1, 1, 0x00, 0, 8},
{FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4, 0, 1, 1, 0x00, 0, 0}, {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B, 0, 1, 1, 0x00, 0, 0},
{0x00, 0, 0, 0, 0, 0x00, 0, 0}, {0x00, 0, 0, 0, 0, 0x00, 0, 0},
}; };
...@@ -553,12 +553,12 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq) ...@@ -553,12 +553,12 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq)
* entering a state that is incompatible with the SPIBoot Controller. * entering a state that is incompatible with the SPIBoot Controller.
*/ */
static struct seq_rw_config stfsm_s25fl_read4_configs[] = { static struct seq_rw_config stfsm_s25fl_read4_configs[] = {
{FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4, 0, 4, 4, 0x00, 2, 4}, {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 2, 4},
{FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4, 0, 1, 4, 0x00, 0, 8}, {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8},
{FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2, 0, 2, 2, 0x00, 4, 0}, {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 4, 0},
{FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2, 0, 1, 2, 0x00, 0, 8}, {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8},
{FLASH_FLAG_READ_FAST, SPINOR_OP_READ4_FAST, 0, 1, 1, 0x00, 0, 8}, {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST_4B, 0, 1, 1, 0x00, 0, 8},
{FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4, 0, 1, 1, 0x00, 0, 0}, {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B, 0, 1, 1, 0x00, 0, 0},
{0x00, 0, 0, 0, 0, 0x00, 0, 0}, {0x00, 0, 0, 0, 0, 0x00, 0, 0},
}; };
......
...@@ -75,7 +75,7 @@ config MTD_PHYSMAP_OF ...@@ -75,7 +75,7 @@ config MTD_PHYSMAP_OF
taken from OF device tree. taken from OF device tree.
config MTD_PHYSMAP_OF_VERSATILE config MTD_PHYSMAP_OF_VERSATILE
bool "Support ARM Versatile physmap OF" bool "ARM Versatile OF-based physical memory map handling"
depends on MTD_PHYSMAP_OF depends on MTD_PHYSMAP_OF
depends on MFD_SYSCON depends on MFD_SYSCON
default y if (ARCH_INTEGRATOR || ARCH_VERSATILE || ARCH_REALVIEW) default y if (ARCH_INTEGRATOR || ARCH_VERSATILE || ARCH_REALVIEW)
...@@ -84,6 +84,16 @@ config MTD_PHYSMAP_OF_VERSATILE ...@@ -84,6 +84,16 @@ config MTD_PHYSMAP_OF_VERSATILE
platforms, basically to add a VPP (write protection) callback so platforms, basically to add a VPP (write protection) callback so
the flash can be taken out of write protection. the flash can be taken out of write protection.
config MTD_PHYSMAP_OF_GEMINI
bool "Cortina Gemini OF-based physical memory map handling"
depends on MTD_PHYSMAP_OF
depends on MFD_SYSCON
default ARCH_GEMINI
help
This provides some extra DT physmap parsing for the Gemini
platforms, some detection and setting up parallel mode on the
external interface.
config MTD_PMC_MSP_EVM config MTD_PMC_MSP_EVM
tristate "CFI Flash device mapped on PMC-Sierra MSP" tristate "CFI Flash device mapped on PMC-Sierra MSP"
depends on PMC_MSP && MTD_CFI depends on PMC_MSP && MTD_CFI
......
...@@ -17,10 +17,13 @@ obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o ...@@ -17,10 +17,13 @@ obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o
obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o
ifdef CONFIG_MTD_PHYSMAP_OF_VERSATILE ifdef CONFIG_MTD_PHYSMAP_OF_VERSATILE
obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of_versatile.o physmap_of-objs += physmap_of_versatile.o
endif
ifdef CONFIG_MTD_PHYSMAP_OF_GEMINI
physmap_of-objs += physmap_of_gemini.o
endif endif
obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o
obj-$(CONFIG_MTD_PISMO) += pismo.o obj-$(CONFIG_MTD_PISMO) += pismo.o
obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o
obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
......
...@@ -57,9 +57,11 @@ static void ichxrom_cleanup(struct ichxrom_window *window) ...@@ -57,9 +57,11 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
{ {
struct ichxrom_map_info *map, *scratch; struct ichxrom_map_info *map, *scratch;
u16 word; u16 word;
int ret;
/* Disable writes through the rom window */ /* Disable writes through the rom window */
pci_read_config_word(window->pdev, BIOS_CNTL, &word); ret = pci_read_config_word(window->pdev, BIOS_CNTL, &word);
if (!ret)
pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1); pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
pci_dev_put(window->pdev); pci_dev_put(window->pdev);
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* by the Free Software Foundation. * by the Free Software Foundation.
* *
* Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE * Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE
* Copyright (C) 2010 John Crispin <blogic@openwrt.org> * Copyright (C) 2010 John Crispin <john@phrozen.org>
*/ */
#include <linux/err.h> #include <linux/err.h>
...@@ -209,5 +209,5 @@ static struct platform_driver ltq_mtd_driver = { ...@@ -209,5 +209,5 @@ static struct platform_driver ltq_mtd_driver = {
module_platform_driver(ltq_mtd_driver); module_platform_driver(ltq_mtd_driver);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); MODULE_AUTHOR("John Crispin <john@phrozen.org>");
MODULE_DESCRIPTION("Lantiq SoC NOR"); MODULE_DESCRIPTION("Lantiq SoC NOR");
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "physmap_of_gemini.h"
#include "physmap_of_versatile.h" #include "physmap_of_versatile.h"
struct of_flash_list { struct of_flash_list {
...@@ -241,11 +242,13 @@ static int of_flash_probe(struct platform_device *dev) ...@@ -241,11 +242,13 @@ static int of_flash_probe(struct platform_device *dev)
info->list[i].map.size = res_size; info->list[i].map.size = res_size;
info->list[i].map.bankwidth = be32_to_cpup(width); info->list[i].map.bankwidth = be32_to_cpup(width);
info->list[i].map.device_node = dp; info->list[i].map.device_node = dp;
err = of_flash_probe_gemini(dev, dp, &info->list[i].map);
if (err)
return err;
err = of_flash_probe_versatile(dev, dp, &info->list[i].map); err = of_flash_probe_versatile(dev, dp, &info->list[i].map);
if (err) { if (err)
dev_err(&dev->dev, "Can't probe Versatile VPP\n");
return err; return err;
}
err = -ENOMEM; err = -ENOMEM;
info->list[i].map.virt = ioremap(info->list[i].map.phys, info->list[i].map.virt = ioremap(info->list[i].map.phys,
......
/*
* Cortina Systems Gemini OF physmap add-on
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
*
* This SoC has an elaborate flash control register, so we need to
* detect and set it up when booting on this platform.
*/
#include <linux/export.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mtd/map.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/bitops.h>
#include "physmap_of_gemini.h"
/*
* The Flash-relevant parts of the global status register
* These would also be relevant for a NAND driver.
*/
#define GLOBAL_STATUS 0x04
#define FLASH_TYPE_MASK (0x3 << 24)
#define FLASH_TYPE_NAND_2K (0x3 << 24)
#define FLASH_TYPE_NAND_512 (0x2 << 24)
#define FLASH_TYPE_PARALLEL (0x1 << 24)
#define FLASH_TYPE_SERIAL (0x0 << 24)
/* if parallel */
#define FLASH_WIDTH_16BIT (1 << 23) /* else 8 bit */
/* if serial */
#define FLASH_ATMEL (1 << 23) /* else STM */
#define FLASH_SIZE_MASK (0x3 << 21)
#define NAND_256M (0x3 << 21) /* and more */
#define NAND_128M (0x2 << 21)
#define NAND_64M (0x1 << 21)
#define NAND_32M (0x0 << 21)
#define ATMEL_16M (0x3 << 21) /* and more */
#define ATMEL_8M (0x2 << 21)
#define ATMEL_4M_2M (0x1 << 21)
#define ATMEL_1M (0x0 << 21) /* and less */
#define STM_32M (1 << 22) /* and more */
#define STM_16M (0 << 22) /* and less */
#define FLASH_PARALLEL_HIGH_PIN_CNT (1 << 20) /* else low pin cnt */
/* Miscellaneous Control Register */
#define GLOBAL_MISC_CTRL 0x30
#define FLASH_PADS_MASK 0x07
#define NAND_PADS_DISABLE BIT(2)
#define PFLASH_PADS_DISABLE BIT(1)
#define SFLASH_PADS_DISABLE BIT(0)
static const struct of_device_id syscon_match[] = {
{ .compatible = "cortina,gemini-syscon" },
{ },
};
int of_flash_probe_gemini(struct platform_device *pdev,
struct device_node *np,
struct map_info *map)
{
static struct regmap *rmap;
struct device *dev = &pdev->dev;
u32 val;
int ret;
/* Multiplatform guard */
if (!of_device_is_compatible(np, "cortina,gemini-flash"))
return 0;
rmap = syscon_regmap_lookup_by_phandle(np, "syscon");
if (IS_ERR(rmap)) {
dev_err(dev, "no syscon\n");
return PTR_ERR(rmap);
}
ret = regmap_read(rmap, GLOBAL_STATUS, &val);
if (ret) {
dev_err(dev, "failed to read global status register\n");
return -ENODEV;
}
dev_dbg(dev, "global status reg: %08x\n", val);
/*
* It would be contradictory if a physmap flash was NOT parallel.
*/
if ((val & FLASH_TYPE_MASK) != FLASH_TYPE_PARALLEL) {
dev_err(dev, "flash is not parallel\n");
return -ENODEV;
}
/*
* Complain if DT data and hardware definition is different.
*/
if (val & FLASH_WIDTH_16BIT) {
if (map->bankwidth != 2)
dev_warn(dev, "flash hardware say flash is 16 bit wide but DT says it is %d bits wide\n",
map->bankwidth * 8);
} else {
if (map->bankwidth != 1)
dev_warn(dev, "flash hardware say flash is 8 bit wide but DT says it is %d bits wide\n",
map->bankwidth * 8);
}
/* Activate parallel (NOR flash) mode */
ret = regmap_update_bits(rmap, GLOBAL_MISC_CTRL,
FLASH_PADS_MASK,
SFLASH_PADS_DISABLE | NAND_PADS_DISABLE);
if (ret) {
dev_err(dev, "unable to set up physmap pads\n");
return -ENODEV;
}
dev_info(&pdev->dev, "initialized Gemini-specific physmap control\n");
return 0;
}
#include <linux/of.h>
#include <linux/mtd/map.h>
#ifdef CONFIG_MTD_PHYSMAP_OF_GEMINI
int of_flash_probe_gemini(struct platform_device *pdev,
struct device_node *np,
struct map_info *map);
#else
static inline
int of_flash_probe_gemini(struct platform_device *pdev,
struct device_node *np,
struct map_info *map)
{
return 0;
}
#endif
...@@ -252,4 +252,3 @@ int of_flash_probe_versatile(struct platform_device *pdev, ...@@ -252,4 +252,3 @@ int of_flash_probe_versatile(struct platform_device *pdev,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(of_flash_probe_versatile);
...@@ -139,15 +139,13 @@ static int __init init_msp_flash(void) ...@@ -139,15 +139,13 @@ static int __init init_msp_flash(void)
} }
msp_maps[i].bankwidth = 1; msp_maps[i].bankwidth = 1;
msp_maps[i].name = kmalloc(7, GFP_KERNEL); msp_maps[i].name = kstrndup(flash_name, 7, GFP_KERNEL);
if (!msp_maps[i].name) { if (!msp_maps[i].name) {
iounmap(msp_maps[i].virt); iounmap(msp_maps[i].virt);
kfree(msp_parts[i]); kfree(msp_parts[i]);
goto cleanup_loop; goto cleanup_loop;
} }
msp_maps[i].name = strncpy(msp_maps[i].name, flash_name, 7);
for (j = 0; j < pcnt; j++) { for (j = 0; j < pcnt; j++) {
part_name[5] = '0' + i; part_name[5] = '0' + i;
part_name[7] = '0' + j; part_name[7] = '0' + j;
......
...@@ -451,7 +451,7 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd, ...@@ -451,7 +451,7 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd,
* data. For our userspace tools it is important to dump areas * data. For our userspace tools it is important to dump areas
* with ECC errors! * with ECC errors!
* For kernel internal usage it also might return -EUCLEAN * For kernel internal usage it also might return -EUCLEAN
* to signal the caller that a bitflip has occured and has * to signal the caller that a bitflip has occurred and has
* been corrected by the ECC algorithm. * been corrected by the ECC algorithm.
* *
* Note: currently the standard NAND function, nand_read_oob_std, * Note: currently the standard NAND function, nand_read_oob_std,
......
...@@ -1128,7 +1128,7 @@ EXPORT_SYMBOL_GPL(mtd_write_oob); ...@@ -1128,7 +1128,7 @@ EXPORT_SYMBOL_GPL(mtd_write_oob);
* @oobecc: OOB region struct filled with the appropriate ECC position * @oobecc: OOB region struct filled with the appropriate ECC position
* information * information
* *
* This functions return ECC section information in the OOB area. I you want * This function returns ECC section information in the OOB area. If you want
* to get all the ECC bytes information, then you should call * to get all the ECC bytes information, then you should call
* mtd_ooblayout_ecc(mtd, section++, oobecc) until it returns -ERANGE. * mtd_ooblayout_ecc(mtd, section++, oobecc) until it returns -ERANGE.
* *
...@@ -1160,7 +1160,7 @@ EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc); ...@@ -1160,7 +1160,7 @@ EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc);
* @oobfree: OOB region struct filled with the appropriate free position * @oobfree: OOB region struct filled with the appropriate free position
* information * information
* *
* This functions return free bytes position in the OOB area. I you want * This function returns free bytes position in the OOB area. If you want
* to get all the free bytes information, then you should call * to get all the free bytes information, then you should call
* mtd_ooblayout_free(mtd, section++, oobfree) until it returns -ERANGE. * mtd_ooblayout_free(mtd, section++, oobfree) until it returns -ERANGE.
* *
...@@ -1190,7 +1190,7 @@ EXPORT_SYMBOL_GPL(mtd_ooblayout_free); ...@@ -1190,7 +1190,7 @@ EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
* @iter: iterator function. Should be either mtd_ooblayout_free or * @iter: iterator function. Should be either mtd_ooblayout_free or
* mtd_ooblayout_ecc depending on the region type you're searching for * mtd_ooblayout_ecc depending on the region type you're searching for
* *
* This functions returns the section id and oobregion information of a * This function returns the section id and oobregion information of a
* specific byte. For example, say you want to know where the 4th ECC byte is * specific byte. For example, say you want to know where the 4th ECC byte is
* stored, you'll use: * stored, you'll use:
* *
......
...@@ -349,6 +349,14 @@ static const struct mtd_ooblayout_ops part_ooblayout_ops = { ...@@ -349,6 +349,14 @@ static const struct mtd_ooblayout_ops part_ooblayout_ops = {
.free = part_ooblayout_free, .free = part_ooblayout_free,
}; };
static int part_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
{
struct mtd_part *part = mtd_to_part(mtd);
return part->master->_max_bad_blocks(part->master,
ofs + part->offset, len);
}
static inline void free_partition(struct mtd_part *p) static inline void free_partition(struct mtd_part *p)
{ {
kfree(p->mtd.name); kfree(p->mtd.name);
...@@ -424,6 +432,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, ...@@ -424,6 +432,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) ? slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) ?
&master->dev : &master->dev :
master->dev.parent; master->dev.parent;
slave->mtd.dev.of_node = part->of_node;
slave->mtd._read = part_read; slave->mtd._read = part_read;
slave->mtd._write = part_write; slave->mtd._write = part_write;
...@@ -475,6 +484,8 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, ...@@ -475,6 +484,8 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd._block_isbad = part_block_isbad; slave->mtd._block_isbad = part_block_isbad;
if (master->_block_markbad) if (master->_block_markbad)
slave->mtd._block_markbad = part_block_markbad; slave->mtd._block_markbad = part_block_markbad;
if (master->_max_bad_blocks)
slave->mtd._max_bad_blocks = part_max_bad_blocks;
if (master->_get_device) if (master->_get_device)
slave->mtd._get_device = part_get_device; slave->mtd._get_device = part_get_device;
......
...@@ -426,6 +426,7 @@ config MTD_NAND_ORION ...@@ -426,6 +426,7 @@ config MTD_NAND_ORION
config MTD_NAND_OXNAS config MTD_NAND_OXNAS
tristate "NAND Flash support for Oxford Semiconductor SoC" tristate "NAND Flash support for Oxford Semiconductor SoC"
depends on ARCH_OXNAS || COMPILE_TEST
depends on HAS_IOMEM depends on HAS_IOMEM
help help
This enables the NAND flash controller on Oxford Semiconductor SoCs. This enables the NAND flash controller on Oxford Semiconductor SoCs.
...@@ -535,6 +536,7 @@ config MTD_NAND_JZ4780 ...@@ -535,6 +536,7 @@ config MTD_NAND_JZ4780
config MTD_NAND_FSMC config MTD_NAND_FSMC
tristate "Support for NAND on ST Micros FSMC" tristate "Support for NAND on ST Micros FSMC"
depends on OF
depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300 depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
help help
Enables support for NAND Flash chips on the ST Microelectronics Enables support for NAND Flash chips on the ST Microelectronics
......
...@@ -258,9 +258,15 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) ...@@ -258,9 +258,15 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
int bufnum = nctrl->page & priv->bufnum_mask; int bufnum = nctrl->page & priv->bufnum_mask;
int sector = bufnum * chip->ecc.steps; int sector = bufnum * chip->ecc.steps;
int sector_end = sector + chip->ecc.steps - 1; int sector_end = sector + chip->ecc.steps - 1;
__be32 *eccstat_regs;
if (ctrl->version >= FSL_IFC_VERSION_2_0_0)
eccstat_regs = ifc->ifc_nand.v2_nand_eccstat;
else
eccstat_regs = ifc->ifc_nand.v1_nand_eccstat;
for (i = sector / 4; i <= sector_end / 4; i++) for (i = sector / 4; i <= sector_end / 4; i++)
eccstat[i] = ifc_in32(&ifc->ifc_nand.nand_eccstat[i]); eccstat[i] = ifc_in32(&eccstat_regs[i]);
for (i = sector; i <= sector_end; i++) { for (i = sector; i <= sector_end; i++) {
errors = check_read_ecc(mtd, ctrl, eccstat, i); errors = check_read_ecc(mtd, ctrl, eccstat, i);
......
...@@ -35,10 +35,133 @@ ...@@ -35,10 +35,133 @@
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mtd/fsmc.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <mtd/mtd-abi.h> #include <mtd/mtd-abi.h>
#define FSMC_NAND_BW8 1
#define FSMC_NAND_BW16 2
#define FSMC_MAX_NOR_BANKS 4
#define FSMC_MAX_NAND_BANKS 4
#define FSMC_FLASH_WIDTH8 1
#define FSMC_FLASH_WIDTH16 2
/* fsmc controller registers for NOR flash */
#define CTRL 0x0
/* ctrl register definitions */
#define BANK_ENABLE (1 << 0)
#define MUXED (1 << 1)
#define NOR_DEV (2 << 2)
#define WIDTH_8 (0 << 4)
#define WIDTH_16 (1 << 4)
#define RSTPWRDWN (1 << 6)
#define WPROT (1 << 7)
#define WRT_ENABLE (1 << 12)
#define WAIT_ENB (1 << 13)
#define CTRL_TIM 0x4
/* ctrl_tim register definitions */
#define FSMC_NOR_BANK_SZ 0x8
#define FSMC_NOR_REG_SIZE 0x40
#define FSMC_NOR_REG(base, bank, reg) (base + \
FSMC_NOR_BANK_SZ * (bank) + \
reg)
/* fsmc controller registers for NAND flash */
#define PC 0x00
/* pc register definitions */
#define FSMC_RESET (1 << 0)
#define FSMC_WAITON (1 << 1)
#define FSMC_ENABLE (1 << 2)
#define FSMC_DEVTYPE_NAND (1 << 3)
#define FSMC_DEVWID_8 (0 << 4)
#define FSMC_DEVWID_16 (1 << 4)
#define FSMC_ECCEN (1 << 6)
#define FSMC_ECCPLEN_512 (0 << 7)
#define FSMC_ECCPLEN_256 (1 << 7)
#define FSMC_TCLR_1 (1)
#define FSMC_TCLR_SHIFT (9)
#define FSMC_TCLR_MASK (0xF)
#define FSMC_TAR_1 (1)
#define FSMC_TAR_SHIFT (13)
#define FSMC_TAR_MASK (0xF)
#define STS 0x04
/* sts register definitions */
#define FSMC_CODE_RDY (1 << 15)
#define COMM 0x08
/* comm register definitions */
#define FSMC_TSET_0 0
#define FSMC_TSET_SHIFT 0
#define FSMC_TSET_MASK 0xFF
#define FSMC_TWAIT_6 6
#define FSMC_TWAIT_SHIFT 8
#define FSMC_TWAIT_MASK 0xFF
#define FSMC_THOLD_4 4
#define FSMC_THOLD_SHIFT 16
#define FSMC_THOLD_MASK 0xFF
#define FSMC_THIZ_1 1
#define FSMC_THIZ_SHIFT 24
#define FSMC_THIZ_MASK 0xFF
#define ATTRIB 0x0C
#define IOATA 0x10
#define ECC1 0x14
#define ECC2 0x18
#define ECC3 0x1C
#define FSMC_NAND_BANK_SZ 0x20
#define FSMC_NAND_REG(base, bank, reg) (base + FSMC_NOR_REG_SIZE + \
(FSMC_NAND_BANK_SZ * (bank)) + \
reg)
#define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ)
struct fsmc_nand_timings {
uint8_t tclr;
uint8_t tar;
uint8_t thiz;
uint8_t thold;
uint8_t twait;
uint8_t tset;
};
enum access_mode {
USE_DMA_ACCESS = 1,
USE_WORD_ACCESS,
};
/**
* fsmc_nand_platform_data - platform specific NAND controller config
* @nand_timings: timing setup for the physical NAND interface
* @partitions: partition table for the platform, use a default fallback
* if this is NULL
* @nr_partitions: the number of partitions in the previous entry
* @options: different options for the driver
* @width: bus width
* @bank: default bank
* @select_bank: callback to select a certain bank, this is
* platform-specific. If the controller only supports one bank
* this may be set to NULL
*/
struct fsmc_nand_platform_data {
struct fsmc_nand_timings *nand_timings;
struct mtd_partition *partitions;
unsigned int nr_partitions;
unsigned int options;
unsigned int width;
unsigned int bank;
enum access_mode mode;
void (*select_bank)(uint32_t bank, uint32_t busw);
/* priv structures for dma accesses */
void *read_dma_priv;
void *write_dma_priv;
};
static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section, static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion) struct mtd_oob_region *oobregion)
{ {
...@@ -714,7 +837,6 @@ static bool filter(struct dma_chan *chan, void *slave) ...@@ -714,7 +837,6 @@ static bool filter(struct dma_chan *chan, void *slave)
return true; return true;
} }
#ifdef CONFIG_OF
static int fsmc_nand_probe_config_dt(struct platform_device *pdev, static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
struct device_node *np) struct device_node *np)
{ {
...@@ -757,13 +879,6 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, ...@@ -757,13 +879,6 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
} }
return 0; return 0;
} }
#else
static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
struct device_node *np)
{
return -ENOSYS;
}
#endif
/* /*
* fsmc_nand_probe - Probe function * fsmc_nand_probe - Probe function
...@@ -782,20 +897,16 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -782,20 +897,16 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
u32 pid; u32 pid;
int i; int i;
if (np) {
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
pdev->dev.platform_data = pdata; pdev->dev.platform_data = pdata;
ret = fsmc_nand_probe_config_dt(pdev, np); ret = fsmc_nand_probe_config_dt(pdev, np);
if (ret) { if (ret) {
dev_err(&pdev->dev, "no platform data\n"); dev_err(&pdev->dev, "no platform data\n");
return -ENODEV; return -ENODEV;
} }
}
if (!pdata) {
dev_err(&pdev->dev, "platform data is NULL\n");
return -EINVAL;
}
/* Allocate memory for the device structure (and zero it) */ /* Allocate memory for the device structure (and zero it) */
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
......
...@@ -797,22 +797,17 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) ...@@ -797,22 +797,17 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
struct resource *rc; struct resource *rc;
int res; int res;
rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (rc == NULL) {
dev_err(&pdev->dev, "No memory resource found for device\n");
return -EBUSY;
}
/* Allocate memory for the device structure (and zero it) */ /* Allocate memory for the device structure (and zero it) */
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
if (!host) if (!host)
return -ENOMEM; return -ENOMEM;
host->io_base_dma = rc->start;
rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->io_base = devm_ioremap_resource(&pdev->dev, rc); host->io_base = devm_ioremap_resource(&pdev->dev, rc);
if (IS_ERR(host->io_base)) if (IS_ERR(host->io_base))
return PTR_ERR(host->io_base); return PTR_ERR(host->io_base);
host->io_base_dma = rc->start;
if (pdev->dev.of_node) if (pdev->dev.of_node)
host->ncfg = lpc32xx_parse_dt(&pdev->dev); host->ncfg = lpc32xx_parse_dt(&pdev->dev);
if (!host->ncfg) { if (!host->ncfg) {
......
...@@ -1383,7 +1383,6 @@ static int mtk_nfc_probe(struct platform_device *pdev) ...@@ -1383,7 +1383,6 @@ static int mtk_nfc_probe(struct platform_device *pdev)
nfc->regs = devm_ioremap_resource(dev, res); nfc->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(nfc->regs)) { if (IS_ERR(nfc->regs)) {
ret = PTR_ERR(nfc->regs); ret = PTR_ERR(nfc->regs);
dev_err(dev, "no nfi base\n");
goto release_ecc; goto release_ecc;
} }
......
...@@ -3262,6 +3262,42 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -3262,6 +3262,42 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
return nand_block_markbad_lowlevel(mtd, ofs); return nand_block_markbad_lowlevel(mtd, ofs);
} }
/**
* nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd
* @mtd: MTD device structure
* @ofs: offset relative to mtd start
* @len: length of mtd
*/
static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
u32 part_start_block;
u32 part_end_block;
u32 part_start_die;
u32 part_end_die;
/*
* max_bb_per_die and blocks_per_die used to determine
* the maximum bad block count.
*/
if (!chip->max_bb_per_die || !chip->blocks_per_die)
return -ENOTSUPP;
/* Get the start and end of the partition in erase blocks. */
part_start_block = mtd_div_by_eb(ofs, mtd);
part_end_block = mtd_div_by_eb(len, mtd) + part_start_block - 1;
/* Get the start and end LUNs of the partition. */
part_start_die = part_start_block / chip->blocks_per_die;
part_end_die = part_end_block / chip->blocks_per_die;
/*
* Look up the bad blocks per unit and multiply by the number of units
* that the partition spans.
*/
return chip->max_bb_per_die * (part_end_die - part_start_die + 1);
}
/** /**
* nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -3592,6 +3628,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -3592,6 +3628,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
chip->bits_per_cell = p->bits_per_cell; chip->bits_per_cell = p->bits_per_cell;
chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);
chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun);
if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS) if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
*busw = NAND_BUSWIDTH_16; *busw = NAND_BUSWIDTH_16;
else else
...@@ -4815,6 +4854,7 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -4815,6 +4854,7 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd->_block_isreserved = nand_block_isreserved; mtd->_block_isreserved = nand_block_isreserved;
mtd->_block_isbad = nand_block_isbad; mtd->_block_isbad = nand_block_isbad;
mtd->_block_markbad = nand_block_markbad; mtd->_block_markbad = nand_block_markbad;
mtd->_max_bad_blocks = nand_max_bad_blocks;
mtd->writebufsize = mtd->writesize; mtd->writebufsize = mtd->writesize;
/* /*
......
...@@ -185,6 +185,7 @@ struct nand_manufacturers nand_manuf_ids[] = { ...@@ -185,6 +185,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_SANDISK, "SanDisk"}, {NAND_MFR_SANDISK, "SanDisk"},
{NAND_MFR_INTEL, "Intel"}, {NAND_MFR_INTEL, "Intel"},
{NAND_MFR_ATO, "ATO"}, {NAND_MFR_ATO, "ATO"},
{NAND_MFR_WINBOND, "Winbond"},
{0x0, "Unknown"} {0x0, "Unknown"}
}; };
......
...@@ -321,6 +321,10 @@ static int sunxi_nfc_wait_events(struct sunxi_nfc *nfc, u32 events, ...@@ -321,6 +321,10 @@ static int sunxi_nfc_wait_events(struct sunxi_nfc *nfc, u32 events,
ret = wait_for_completion_timeout(&nfc->complete, ret = wait_for_completion_timeout(&nfc->complete,
msecs_to_jiffies(timeout_ms)); msecs_to_jiffies(timeout_ms));
if (!ret)
ret = -ETIMEDOUT;
else
ret = 0;
writel(0, nfc->regs + NFC_REG_INT); writel(0, nfc->regs + NFC_REG_INT);
} else { } else {
...@@ -518,6 +522,8 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) ...@@ -518,6 +522,8 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
u32 tmp; u32 tmp;
while (len > offs) { while (len > offs) {
bool poll = false;
cnt = min(len - offs, NFC_SRAM_SIZE); cnt = min(len - offs, NFC_SRAM_SIZE);
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
...@@ -528,7 +534,11 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) ...@@ -528,7 +534,11 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD; tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
writel(tmp, nfc->regs + NFC_REG_CMD); writel(tmp, nfc->regs + NFC_REG_CMD);
ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0); /* Arbitrary limit for polling mode */
if (cnt < 64)
poll = true;
ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
if (ret) if (ret)
break; break;
...@@ -551,6 +561,8 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, ...@@ -551,6 +561,8 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
u32 tmp; u32 tmp;
while (len > offs) { while (len > offs) {
bool poll = false;
cnt = min(len - offs, NFC_SRAM_SIZE); cnt = min(len - offs, NFC_SRAM_SIZE);
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
...@@ -563,7 +575,11 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, ...@@ -563,7 +575,11 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
NFC_ACCESS_DIR; NFC_ACCESS_DIR;
writel(tmp, nfc->regs + NFC_REG_CMD); writel(tmp, nfc->regs + NFC_REG_CMD);
ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0); /* Arbitrary limit for polling mode */
if (cnt < 64)
poll = true;
ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
if (ret) if (ret)
break; break;
...@@ -588,10 +604,6 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, ...@@ -588,10 +604,6 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
int ret; int ret;
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
if (ret)
return;
if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) && if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) &&
!(ctrl & (NAND_CLE | NAND_ALE))) { !(ctrl & (NAND_CLE | NAND_ALE))) {
u32 cmd = 0; u32 cmd = 0;
...@@ -621,6 +633,10 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, ...@@ -621,6 +633,10 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
writel(sunxi_nand->addr[1], writel(sunxi_nand->addr[1],
nfc->regs + NFC_REG_ADDR_HIGH); nfc->regs + NFC_REG_ADDR_HIGH);
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
if (ret)
return;
writel(cmd, nfc->regs + NFC_REG_CMD); writel(cmd, nfc->regs + NFC_REG_CMD);
sunxi_nand->addr[0] = 0; sunxi_nand->addr[0] = 0;
sunxi_nand->addr[1] = 0; sunxi_nand->addr[1] = 0;
...@@ -957,7 +973,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, ...@@ -957,7 +973,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP, writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
nfc->regs + NFC_REG_CMD); nfc->regs + NFC_REG_CMD);
ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0); ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
sunxi_nfc_randomizer_disable(mtd); sunxi_nfc_randomizer_disable(mtd);
if (ret) if (ret)
return ret; return ret;
...@@ -1069,7 +1085,7 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf, ...@@ -1069,7 +1085,7 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS, writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS,
nfc->regs + NFC_REG_CMD); nfc->regs + NFC_REG_CMD);
ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0); ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
if (ret) if (ret)
dmaengine_terminate_all(nfc->dmac); dmaengine_terminate_all(nfc->dmac);
...@@ -1189,7 +1205,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, ...@@ -1189,7 +1205,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
NFC_ACCESS_DIR | NFC_ECC_OP, NFC_ACCESS_DIR | NFC_ECC_OP,
nfc->regs + NFC_REG_CMD); nfc->regs + NFC_REG_CMD);
ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0); ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
sunxi_nfc_randomizer_disable(mtd); sunxi_nfc_randomizer_disable(mtd);
if (ret) if (ret)
return ret; return ret;
...@@ -1428,7 +1444,7 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd, ...@@ -1428,7 +1444,7 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
NFC_DATA_TRANS | NFC_ACCESS_DIR, NFC_DATA_TRANS | NFC_ACCESS_DIR,
nfc->regs + NFC_REG_CMD); nfc->regs + NFC_REG_CMD);
ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0); ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
if (ret) if (ret)
dmaengine_terminate_all(nfc->dmac); dmaengine_terminate_all(nfc->dmac);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* under the terms of the GNU General Public License version 2 as published * under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. * by the Free Software Foundation.
* *
* Copyright © 2012 John Crispin <blogic@openwrt.org> * Copyright © 2012 John Crispin <john@phrozen.org>
* Copyright © 2016 Hauke Mehrtens <hauke@hauke-m.de> * Copyright © 2016 Hauke Mehrtens <hauke@hauke-m.de>
*/ */
......
...@@ -108,6 +108,7 @@ static int parse_ofpart_partitions(struct mtd_info *master, ...@@ -108,6 +108,7 @@ static int parse_ofpart_partitions(struct mtd_info *master,
parts[i].offset = of_read_number(reg, a_cells); parts[i].offset = of_read_number(reg, a_cells);
parts[i].size = of_read_number(reg + a_cells, s_cells); parts[i].size = of_read_number(reg + a_cells, s_cells);
parts[i].of_node = pp;
partname = of_get_property(pp, "label", &len); partname = of_get_property(pp, "label", &len);
if (!partname) if (!partname)
......
...@@ -29,6 +29,16 @@ config MTD_SPI_NOR_USE_4K_SECTORS ...@@ -29,6 +29,16 @@ config MTD_SPI_NOR_USE_4K_SECTORS
Please note that some tools/drivers/filesystems may not work with Please note that some tools/drivers/filesystems may not work with
4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum). 4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum).
config SPI_ASPEED_SMC
tristate "Aspeed flash controllers in SPI mode"
depends on ARCH_ASPEED || COMPILE_TEST
depends on HAS_IOMEM && OF
help
This enables support for the Firmware Memory controller (FMC)
in the Aspeed AST2500/AST2400 SoCs when attached to SPI NOR chips,
and support for the SPI flash memory controller (SPI) for
the host firmware. The implementation only supports SPI NOR.
config SPI_ATMEL_QUADSPI config SPI_ATMEL_QUADSPI
tristate "Atmel Quad SPI Controller" tristate "Atmel Quad SPI Controller"
depends on ARCH_AT91 || (ARM && COMPILE_TEST) depends on ARCH_AT91 || (ARM && COMPILE_TEST)
...@@ -40,7 +50,7 @@ config SPI_ATMEL_QUADSPI ...@@ -40,7 +50,7 @@ config SPI_ATMEL_QUADSPI
config SPI_CADENCE_QUADSPI config SPI_CADENCE_QUADSPI
tristate "Cadence Quad SPI controller" tristate "Cadence Quad SPI controller"
depends on OF && ARM depends on OF && (ARM || COMPILE_TEST)
help help
Enable support for the Cadence Quad SPI Flash controller. Enable support for the Cadence Quad SPI Flash controller.
...@@ -76,4 +86,24 @@ config SPI_NXP_SPIFI ...@@ -76,4 +86,24 @@ config SPI_NXP_SPIFI
Flash. Enable this option if you have a device with a SPIFI Flash. Enable this option if you have a device with a SPIFI
controller and want to access the Flash as a mtd device. controller and want to access the Flash as a mtd device.
config SPI_INTEL_SPI
tristate
config SPI_INTEL_SPI_PLATFORM
tristate "Intel PCH/PCU SPI flash platform driver" if EXPERT
depends on X86
select SPI_INTEL_SPI
help
This enables platform support for the Intel PCH/PCU SPI
controller in master mode. This controller is present in modern
Intel hardware and is used to hold BIOS and other persistent
settings. Using this driver it is possible to upgrade BIOS
directly from Linux.
Say N here unless you know what you are doing. Overwriting the
SPI flash may render the system unbootable.
To compile this driver as a module, choose M here: the module
will be called intel-spi-platform.
endif # MTD_SPI_NOR endif # MTD_SPI_NOR
obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
obj-$(CONFIG_SPI_ASPEED_SMC) += aspeed-smc.o
obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o
obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o
obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o
obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o
obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o
obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o
This diff is collapsed.
...@@ -526,7 +526,8 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor, ...@@ -526,7 +526,8 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor,
bytes_to_read *= cqspi->fifo_width; bytes_to_read *= cqspi->fifo_width;
bytes_to_read = bytes_to_read > remaining ? bytes_to_read = bytes_to_read > remaining ?
remaining : bytes_to_read; remaining : bytes_to_read;
readsl(ahb_base, rxbuf, DIV_ROUND_UP(bytes_to_read, 4)); ioread32_rep(ahb_base, rxbuf,
DIV_ROUND_UP(bytes_to_read, 4));
rxbuf += bytes_to_read; rxbuf += bytes_to_read;
remaining -= bytes_to_read; remaining -= bytes_to_read;
bytes_to_read = cqspi_get_rd_sram_level(cqspi); bytes_to_read = cqspi_get_rd_sram_level(cqspi);
...@@ -610,7 +611,8 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor, ...@@ -610,7 +611,8 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor,
while (remaining > 0) { while (remaining > 0) {
write_bytes = remaining > page_size ? page_size : remaining; write_bytes = remaining > page_size ? page_size : remaining;
writesl(cqspi->ahb_base, txbuf, DIV_ROUND_UP(write_bytes, 4)); iowrite32_rep(cqspi->ahb_base, txbuf,
DIV_ROUND_UP(write_bytes, 4));
ret = wait_for_completion_timeout(&cqspi->transfer_complete, ret = wait_for_completion_timeout(&cqspi->transfer_complete,
msecs_to_jiffies msecs_to_jiffies
...@@ -891,7 +893,7 @@ static ssize_t cqspi_write(struct spi_nor *nor, loff_t to, ...@@ -891,7 +893,7 @@ static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
if (ret) if (ret)
return ret; return ret;
return (ret < 0) ? ret : len; return len;
} }
static ssize_t cqspi_read(struct spi_nor *nor, loff_t from, static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
...@@ -911,7 +913,7 @@ static ssize_t cqspi_read(struct spi_nor *nor, loff_t from, ...@@ -911,7 +913,7 @@ static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
if (ret) if (ret)
return ret; return ret;
return (ret < 0) ? ret : len; return len;
} }
static int cqspi_erase(struct spi_nor *nor, loff_t offs) static int cqspi_erase(struct spi_nor *nor, loff_t offs)
......
...@@ -193,7 +193,7 @@ ...@@ -193,7 +193,7 @@
#define QUADSPI_LUT_NUM 64 #define QUADSPI_LUT_NUM 64
/* SEQID -- we can have 16 seqids at most. */ /* SEQID -- we can have 16 seqids at most. */
#define SEQID_QUAD_READ 0 #define SEQID_READ 0
#define SEQID_WREN 1 #define SEQID_WREN 1
#define SEQID_WRDI 2 #define SEQID_WRDI 2
#define SEQID_RDSR 3 #define SEQID_RDSR 3
...@@ -373,32 +373,26 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) ...@@ -373,32 +373,26 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
void __iomem *base = q->iobase; void __iomem *base = q->iobase;
int rxfifo = q->devtype_data->rxfifo; int rxfifo = q->devtype_data->rxfifo;
u32 lut_base; u32 lut_base;
u8 cmd, addrlen, dummy;
int i; int i;
struct spi_nor *nor = &q->nor[0];
u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
u8 read_op = nor->read_opcode;
u8 read_dm = nor->read_dummy;
fsl_qspi_unlock_lut(q); fsl_qspi_unlock_lut(q);
/* Clear all the LUT table */ /* Clear all the LUT table */
for (i = 0; i < QUADSPI_LUT_NUM; i++) for (i = 0; i < QUADSPI_LUT_NUM; i++)
qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4); qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4);
/* Quad Read */ /* Read */
lut_base = SEQID_QUAD_READ * 4; lut_base = SEQID_READ * 4;
if (q->nor_size <= SZ_16M) {
cmd = SPINOR_OP_READ_1_1_4;
addrlen = ADDR24BIT;
dummy = 8;
} else {
/* use the 4-byte address */
cmd = SPINOR_OP_READ_1_1_4;
addrlen = ADDR32BIT;
dummy = 8;
}
qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), qspi_writel(q, LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD1, addrlen),
base + QUADSPI_LUT(lut_base)); base + QUADSPI_LUT(lut_base));
qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo), qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) |
LUT1(FSL_READ, PAD4, rxfifo),
base + QUADSPI_LUT(lut_base + 1)); base + QUADSPI_LUT(lut_base + 1));
/* Write enable */ /* Write enable */
...@@ -409,16 +403,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) ...@@ -409,16 +403,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
/* Page Program */ /* Page Program */
lut_base = SEQID_PP * 4; lut_base = SEQID_PP * 4;
if (q->nor_size <= SZ_16M) { qspi_writel(q, LUT0(CMD, PAD1, nor->program_opcode) |
cmd = SPINOR_OP_PP; LUT1(ADDR, PAD1, addrlen),
addrlen = ADDR24BIT;
} else {
/* use the 4-byte address */
cmd = SPINOR_OP_PP;
addrlen = ADDR32BIT;
}
qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
base + QUADSPI_LUT(lut_base)); base + QUADSPI_LUT(lut_base));
qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0), qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0),
base + QUADSPI_LUT(lut_base + 1)); base + QUADSPI_LUT(lut_base + 1));
...@@ -432,10 +418,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) ...@@ -432,10 +418,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
/* Erase a sector */ /* Erase a sector */
lut_base = SEQID_SE * 4; lut_base = SEQID_SE * 4;
cmd = q->nor[0].erase_opcode; qspi_writel(q, LUT0(CMD, PAD1, nor->erase_opcode) |
addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT; LUT1(ADDR, PAD1, addrlen),
qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
base + QUADSPI_LUT(lut_base)); base + QUADSPI_LUT(lut_base));
/* Erase the whole chip */ /* Erase the whole chip */
...@@ -484,7 +468,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) ...@@ -484,7 +468,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
{ {
switch (cmd) { switch (cmd) {
case SPINOR_OP_READ_1_1_4: case SPINOR_OP_READ_1_1_4:
return SEQID_QUAD_READ; return SEQID_READ;
case SPINOR_OP_WREN: case SPINOR_OP_WREN:
return SEQID_WREN; return SEQID_WREN;
case SPINOR_OP_WRDI: case SPINOR_OP_WRDI:
......
/*
* Intel PCH/PCU SPI flash platform driver.
*
* Copyright (C) 2016, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "intel-spi.h"
static int intel_spi_platform_probe(struct platform_device *pdev)
{
struct intel_spi_boardinfo *info;
struct intel_spi *ispi;
struct resource *mem;
info = dev_get_platdata(&pdev->dev);
if (!info)
return -EINVAL;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ispi = intel_spi_probe(&pdev->dev, mem, info);
if (IS_ERR(ispi))
return PTR_ERR(ispi);
platform_set_drvdata(pdev, ispi);
return 0;
}
static int intel_spi_platform_remove(struct platform_device *pdev)
{
struct intel_spi *ispi = platform_get_drvdata(pdev);
return intel_spi_remove(ispi);
}
static struct platform_driver intel_spi_platform_driver = {
.probe = intel_spi_platform_probe,
.remove = intel_spi_platform_remove,
.driver = {
.name = "intel-spi",
},
};
module_platform_driver(intel_spi_platform_driver);
MODULE_DESCRIPTION("Intel PCH/PCU SPI flash platform driver");
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:intel-spi");
This diff is collapsed.
/*
* Intel PCH/PCU SPI flash driver.
*
* Copyright (C) 2016, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef INTEL_SPI_H
#define INTEL_SPI_H
#include <linux/platform_data/intel-spi.h>
struct intel_spi;
struct resource;
struct intel_spi *intel_spi_probe(struct device *dev,
struct resource *mem, const struct intel_spi_boardinfo *info);
int intel_spi_remove(struct intel_spi *ispi);
#endif /* INTEL_SPI_H */
This diff is collapsed.
...@@ -371,7 +371,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, int width, ...@@ -371,7 +371,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, int width,
/* default mode, does not need flex_cmd */ /* default mode, does not need flex_cmd */
flex_mode = 0; flex_mode = 0;
else else
command = SPINOR_OP_READ4_FAST; command = SPINOR_OP_READ_FAST_4B;
break; break;
case SPI_NBITS_DUAL: case SPI_NBITS_DUAL:
bpc = 0x00000001; bpc = 0x00000001;
...@@ -384,7 +384,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, int width, ...@@ -384,7 +384,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, int width,
} else { } else {
command = SPINOR_OP_READ_1_1_2; command = SPINOR_OP_READ_1_1_2;
if (spans_4byte) if (spans_4byte)
command = SPINOR_OP_READ4_1_1_2; command = SPINOR_OP_READ_1_1_2_4B;
} }
break; break;
case SPI_NBITS_QUAD: case SPI_NBITS_QUAD:
...@@ -399,7 +399,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, int width, ...@@ -399,7 +399,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, int width,
} else { } else {
command = SPINOR_OP_READ_1_1_4; command = SPINOR_OP_READ_1_1_4;
if (spans_4byte) if (spans_4byte)
command = SPINOR_OP_READ4_1_1_4; command = SPINOR_OP_READ_1_1_4_4B;
} }
break; break;
default: default:
......
...@@ -593,9 +593,6 @@ struct bcma_sflash { ...@@ -593,9 +593,6 @@ struct bcma_sflash {
u32 blocksize; u32 blocksize;
u16 numblocks; u16 numblocks;
u32 size; u32 size;
struct mtd_info *mtd;
void *priv;
}; };
#endif #endif
......
...@@ -733,8 +733,12 @@ struct fsl_ifc_nand { ...@@ -733,8 +733,12 @@ struct fsl_ifc_nand {
__be32 nand_erattr1; __be32 nand_erattr1;
u32 res19[0x10]; u32 res19[0x10];
__be32 nand_fsr; __be32 nand_fsr;
u32 res20[0x3]; u32 res20;
__be32 nand_eccstat[6]; /* The V1 nand_eccstat is actually 4 words that overlaps the
* V2 nand_eccstat.
*/
__be32 v1_nand_eccstat[2];
__be32 v2_nand_eccstat[6];
u32 res21[0x1c]; u32 res21[0x1c];
__be32 nanndcr; __be32 nanndcr;
u32 res22[0x2]; u32 res22[0x2];
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#ifndef LPC_ICH_H #ifndef LPC_ICH_H
#define LPC_ICH_H #define LPC_ICH_H
#include <linux/platform_data/intel-spi.h>
/* GPIO resources */ /* GPIO resources */
#define ICH_RES_GPIO 0 #define ICH_RES_GPIO 0
#define ICH_RES_GPE0 1 #define ICH_RES_GPE0 1
...@@ -40,6 +42,7 @@ struct lpc_ich_info { ...@@ -40,6 +42,7 @@ struct lpc_ich_info {
char name[32]; char name[32];
unsigned int iTCO_version; unsigned int iTCO_version;
unsigned int gpio_version; unsigned int gpio_version;
enum intel_spi_type spi_type;
u8 use_gpio; u8 use_gpio;
}; };
......
/*
* incude/mtd/fsmc.h
*
* ST Microelectronics
* Flexible Static Memory Controller (FSMC)
* platform data interface and header file
*
* Copyright © 2010 ST Microelectronics
* Vipin Kumar <vipin.kumar@st.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __MTD_FSMC_H
#define __MTD_FSMC_H
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/mtd/physmap.h>
#include <linux/types.h>
#include <linux/mtd/partitions.h>
#include <asm/param.h>
#define FSMC_NAND_BW8 1
#define FSMC_NAND_BW16 2
#define FSMC_MAX_NOR_BANKS 4
#define FSMC_MAX_NAND_BANKS 4
#define FSMC_FLASH_WIDTH8 1
#define FSMC_FLASH_WIDTH16 2
/* fsmc controller registers for NOR flash */
#define CTRL 0x0
/* ctrl register definitions */
#define BANK_ENABLE (1 << 0)
#define MUXED (1 << 1)
#define NOR_DEV (2 << 2)
#define WIDTH_8 (0 << 4)
#define WIDTH_16 (1 << 4)
#define RSTPWRDWN (1 << 6)
#define WPROT (1 << 7)
#define WRT_ENABLE (1 << 12)
#define WAIT_ENB (1 << 13)
#define CTRL_TIM 0x4
/* ctrl_tim register definitions */
#define FSMC_NOR_BANK_SZ 0x8
#define FSMC_NOR_REG_SIZE 0x40
#define FSMC_NOR_REG(base, bank, reg) (base + \
FSMC_NOR_BANK_SZ * (bank) + \
reg)
/* fsmc controller registers for NAND flash */
#define PC 0x00
/* pc register definitions */
#define FSMC_RESET (1 << 0)
#define FSMC_WAITON (1 << 1)
#define FSMC_ENABLE (1 << 2)
#define FSMC_DEVTYPE_NAND (1 << 3)
#define FSMC_DEVWID_8 (0 << 4)
#define FSMC_DEVWID_16 (1 << 4)
#define FSMC_ECCEN (1 << 6)
#define FSMC_ECCPLEN_512 (0 << 7)
#define FSMC_ECCPLEN_256 (1 << 7)
#define FSMC_TCLR_1 (1)
#define FSMC_TCLR_SHIFT (9)
#define FSMC_TCLR_MASK (0xF)
#define FSMC_TAR_1 (1)
#define FSMC_TAR_SHIFT (13)
#define FSMC_TAR_MASK (0xF)
#define STS 0x04
/* sts register definitions */
#define FSMC_CODE_RDY (1 << 15)
#define COMM 0x08
/* comm register definitions */
#define FSMC_TSET_0 0
#define FSMC_TSET_SHIFT 0
#define FSMC_TSET_MASK 0xFF
#define FSMC_TWAIT_6 6
#define FSMC_TWAIT_SHIFT 8
#define FSMC_TWAIT_MASK 0xFF
#define FSMC_THOLD_4 4
#define FSMC_THOLD_SHIFT 16
#define FSMC_THOLD_MASK 0xFF
#define FSMC_THIZ_1 1
#define FSMC_THIZ_SHIFT 24
#define FSMC_THIZ_MASK 0xFF
#define ATTRIB 0x0C
#define IOATA 0x10
#define ECC1 0x14
#define ECC2 0x18
#define ECC3 0x1C
#define FSMC_NAND_BANK_SZ 0x20
#define FSMC_NAND_REG(base, bank, reg) (base + FSMC_NOR_REG_SIZE + \
(FSMC_NAND_BANK_SZ * (bank)) + \
reg)
#define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ)
struct fsmc_nand_timings {
uint8_t tclr;
uint8_t tar;
uint8_t thiz;
uint8_t thold;
uint8_t twait;
uint8_t tset;
};
enum access_mode {
USE_DMA_ACCESS = 1,
USE_WORD_ACCESS,
};
/**
* fsmc_nand_platform_data - platform specific NAND controller config
* @nand_timings: timing setup for the physical NAND interface
* @partitions: partition table for the platform, use a default fallback
* if this is NULL
* @nr_partitions: the number of partitions in the previous entry
* @options: different options for the driver
* @width: bus width
* @bank: default bank
* @select_bank: callback to select a certain bank, this is
* platform-specific. If the controller only supports one bank
* this may be set to NULL
*/
struct fsmc_nand_platform_data {
struct fsmc_nand_timings *nand_timings;
struct mtd_partition *partitions;
unsigned int nr_partitions;
unsigned int options;
unsigned int width;
unsigned int bank;
enum access_mode mode;
void (*select_bank)(uint32_t bank, uint32_t busw);
/* priv structures for dma accesses */
void *read_dma_priv;
void *write_dma_priv;
};
extern int __init fsmc_nor_init(struct platform_device *pdev,
unsigned long base, uint32_t bank, uint32_t width);
extern void __init fsmc_init_board_info(struct platform_device *pdev,
struct mtd_partition *partitions, unsigned int nr_partitions,
unsigned int width);
#endif /* __MTD_FSMC_H */
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/of.h>
#include <mtd/mtd-abi.h> #include <mtd/mtd-abi.h>
...@@ -322,6 +323,7 @@ struct mtd_info { ...@@ -322,6 +323,7 @@ struct mtd_info {
int (*_block_isreserved) (struct mtd_info *mtd, loff_t ofs); int (*_block_isreserved) (struct mtd_info *mtd, loff_t ofs);
int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs); int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs); int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
int (*_max_bad_blocks) (struct mtd_info *mtd, loff_t ofs, size_t len);
int (*_suspend) (struct mtd_info *mtd); int (*_suspend) (struct mtd_info *mtd);
void (*_resume) (struct mtd_info *mtd); void (*_resume) (struct mtd_info *mtd);
void (*_reboot) (struct mtd_info *mtd); void (*_reboot) (struct mtd_info *mtd);
...@@ -385,6 +387,8 @@ static inline void mtd_set_of_node(struct mtd_info *mtd, ...@@ -385,6 +387,8 @@ static inline void mtd_set_of_node(struct mtd_info *mtd,
struct device_node *np) struct device_node *np)
{ {
mtd->dev.of_node = np; mtd->dev.of_node = np;
if (!mtd->name)
of_property_read_string(np, "label", &mtd->name);
} }
static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd) static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd)
...@@ -397,6 +401,18 @@ static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops) ...@@ -397,6 +401,18 @@ static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
} }
static inline int mtd_max_bad_blocks(struct mtd_info *mtd,
loff_t ofs, size_t len)
{
if (!mtd->_max_bad_blocks)
return -ENOTSUPP;
if (mtd->size < (len + ofs) || ofs < 0)
return -EINVAL;
return mtd->_max_bad_blocks(mtd, ofs, len);
}
int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit, int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit,
struct mtd_pairing_info *info); struct mtd_pairing_info *info);
int mtd_pairing_info_to_wunit(struct mtd_info *mtd, int mtd_pairing_info_to_wunit(struct mtd_info *mtd,
......
...@@ -615,7 +615,7 @@ struct nand_buffers { ...@@ -615,7 +615,7 @@ struct nand_buffers {
* @tALS_min: ALE setup time * @tALS_min: ALE setup time
* @tAR_min: ALE to RE# delay * @tAR_min: ALE to RE# delay
* @tCEA_max: CE# access time * @tCEA_max: CE# access time
* @tCEH_min: * @tCEH_min: CE# high hold time
* @tCH_min: CE# hold time * @tCH_min: CE# hold time
* @tCHZ_max: CE# high to output hi-Z * @tCHZ_max: CE# high to output hi-Z
* @tCLH_min: CLE hold time * @tCLH_min: CLE hold time
...@@ -801,6 +801,10 @@ nand_get_sdr_timings(const struct nand_data_interface *conf) ...@@ -801,6 +801,10 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
* supported, 0 otherwise. * supported, 0 otherwise.
* @jedec_params: [INTERN] holds the JEDEC parameter page when JEDEC is * @jedec_params: [INTERN] holds the JEDEC parameter page when JEDEC is
* supported, 0 otherwise. * supported, 0 otherwise.
* @max_bb_per_die: [INTERN] the max number of bad blocks each die of a
* this nand device will encounter their life times.
* @blocks_per_die: [INTERN] The number of PEBs in a die
* @data_interface: [INTERN] NAND interface timing information
* @read_retries: [INTERN] the number of read retry modes supported * @read_retries: [INTERN] the number of read retry modes supported
* @onfi_set_features: [REPLACEABLE] set the features for ONFI nand * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
* @onfi_get_features: [REPLACEABLE] get the features for ONFI nand * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
...@@ -883,6 +887,8 @@ struct nand_chip { ...@@ -883,6 +887,8 @@ struct nand_chip {
struct nand_onfi_params onfi_params; struct nand_onfi_params onfi_params;
struct nand_jedec_params jedec_params; struct nand_jedec_params jedec_params;
}; };
u16 max_bb_per_die;
u32 blocks_per_die;
struct nand_data_interface *data_interface; struct nand_data_interface *data_interface;
...@@ -958,6 +964,7 @@ static inline void nand_set_controller_data(struct nand_chip *chip, void *priv) ...@@ -958,6 +964,7 @@ static inline void nand_set_controller_data(struct nand_chip *chip, void *priv)
#define NAND_MFR_SANDISK 0x45 #define NAND_MFR_SANDISK 0x45
#define NAND_MFR_INTEL 0x89 #define NAND_MFR_INTEL 0x89
#define NAND_MFR_ATO 0x9b #define NAND_MFR_ATO 0x9b
#define NAND_MFR_WINBOND 0xef
/* The maximum expected count of bytes in the NAND ID sequence */ /* The maximum expected count of bytes in the NAND ID sequence */
#define NAND_MAX_ID_LEN 8 #define NAND_MAX_ID_LEN 8
......
...@@ -41,6 +41,7 @@ struct mtd_partition { ...@@ -41,6 +41,7 @@ struct mtd_partition {
uint64_t size; /* partition size */ uint64_t size; /* partition size */
uint64_t offset; /* offset within the master MTD space */ uint64_t offset; /* offset within the master MTD space */
uint32_t mask_flags; /* master MTD flags to mask out for this partition */ uint32_t mask_flags; /* master MTD flags to mask out for this partition */
struct device_node *of_node;
}; };
#define MTDPART_OFS_RETAIN (-3) #define MTDPART_OFS_RETAIN (-3)
......
...@@ -43,9 +43,13 @@ ...@@ -43,9 +43,13 @@
#define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */ #define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */
#define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */ #define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */
#define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */ #define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */
#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */ #define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual Output SPI) */
#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */ #define SPINOR_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */
#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Output SPI) */
#define SPINOR_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */
#define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */ #define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */
#define SPINOR_OP_PP_1_1_4 0x32 /* Quad page program */
#define SPINOR_OP_PP_1_4_4 0x38 /* Quad page program */
#define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */ #define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */
#define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ #define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
#define SPINOR_OP_BE_32K 0x52 /* Erase 32KiB block */ #define SPINOR_OP_BE_32K 0x52 /* Erase 32KiB block */
...@@ -56,11 +60,17 @@ ...@@ -56,11 +60,17 @@
#define SPINOR_OP_RDFSR 0x70 /* Read flag status register */ #define SPINOR_OP_RDFSR 0x70 /* Read flag status register */
/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
#define SPINOR_OP_READ4 0x13 /* Read data bytes (low frequency) */ #define SPINOR_OP_READ_4B 0x13 /* Read data bytes (low frequency) */
#define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */ #define SPINOR_OP_READ_FAST_4B 0x0c /* Read data bytes (high frequency) */
#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */ #define SPINOR_OP_READ_1_1_2_4B 0x3c /* Read data bytes (Dual Output SPI) */
#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */ #define SPINOR_OP_READ_1_2_2_4B 0xbc /* Read data bytes (Dual I/O SPI) */
#define SPINOR_OP_READ_1_1_4_4B 0x6c /* Read data bytes (Quad Output SPI) */
#define SPINOR_OP_READ_1_4_4_4B 0xec /* Read data bytes (Quad I/O SPI) */
#define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */ #define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */
#define SPINOR_OP_PP_1_1_4_4B 0x34 /* Quad page program */
#define SPINOR_OP_PP_1_4_4_4B 0x3e /* Quad page program */
#define SPINOR_OP_BE_4K_4B 0x21 /* Erase 4KiB block */
#define SPINOR_OP_BE_32K_4B 0x5c /* Erase 32KiB block */
#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */ #define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */
/* Used for SST flashes only. */ /* Used for SST flashes only. */
...@@ -68,6 +78,15 @@ ...@@ -68,6 +78,15 @@
#define SPINOR_OP_WRDI 0x04 /* Write disable */ #define SPINOR_OP_WRDI 0x04 /* Write disable */
#define SPINOR_OP_AAI_WP 0xad /* Auto address increment word program */ #define SPINOR_OP_AAI_WP 0xad /* Auto address increment word program */
/* Used for S3AN flashes only */
#define SPINOR_OP_XSE 0x50 /* Sector erase */
#define SPINOR_OP_XPP 0x82 /* Page program */
#define SPINOR_OP_XRDSR 0xd7 /* Read status register */
#define XSR_PAGESIZE BIT(0) /* Page size in Po2 or Linear */
#define XSR_RDY BIT(7) /* Ready */
/* Used for Macronix and Winbond flashes. */ /* Used for Macronix and Winbond flashes. */
#define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */ #define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */
#define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */ #define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */
...@@ -119,6 +138,9 @@ enum spi_nor_ops { ...@@ -119,6 +138,9 @@ enum spi_nor_ops {
enum spi_nor_option_flags { enum spi_nor_option_flags {
SNOR_F_USE_FSR = BIT(0), SNOR_F_USE_FSR = BIT(0),
SNOR_F_HAS_SR_TB = BIT(1), SNOR_F_HAS_SR_TB = BIT(1),
SNOR_F_NO_OP_CHIP_ERASE = BIT(2),
SNOR_F_S3AN_ADDR_DEFAULT = BIT(3),
SNOR_F_READY_XSR_RDY = BIT(4),
}; };
/** /**
......
/*
* Intel PCH/PCU SPI flash driver.
*
* Copyright (C) 2016, Intel Corporation
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef INTEL_SPI_PDATA_H
#define INTEL_SPI_PDATA_H
enum intel_spi_type {
INTEL_SPI_BYT = 1,
INTEL_SPI_LPT,
INTEL_SPI_BXT,
};
/**
* struct intel_spi_boardinfo - Board specific data for Intel SPI driver
* @type: Type which this controller is compatible with
* @writeable: The chip is writeable
*/
struct intel_spi_boardinfo {
enum intel_spi_type type;
bool writeable;
};
#endif /* INTEL_SPI_PDATA_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment