mtd: spi-nor: intel-spi: Add support for Intel Denverton SPI serial flash controller
authorMika Westerberg <mika.westerberg@linux.intel.com>
Thu, 29 Jun 2017 11:45:42 +0000 (14:45 +0300)
committerCyrille Pitchen <cyrille.pitchen@free-electrons.com>
Tue, 1 Aug 2017 17:19:28 +0000 (19:19 +0200)
Intel Denverton exposes the SPI serial flash controller as a PCI device
instead of being part of the LPC chip as previous generations did.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
drivers/mtd/spi-nor/Kconfig
drivers/mtd/spi-nor/Makefile
drivers/mtd/spi-nor/intel-spi-pci.c [new file with mode: 0644]

index 293c8a4d1e49660717736d2a951d7f851be1a651..69c638dd04848be10540cdd26e1c0327833d3668 100644 (file)
@@ -89,6 +89,22 @@ config SPI_NXP_SPIFI
 config SPI_INTEL_SPI
        tristate
 
+config SPI_INTEL_SPI_PCI
+       tristate "Intel PCH/PCU SPI flash PCI driver" if EXPERT
+       depends on X86 && PCI
+       select SPI_INTEL_SPI
+       help
+         This enables PCI 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-pci.
+
 config SPI_INTEL_SPI_PLATFORM
        tristate "Intel PCH/PCU SPI flash platform driver" if EXPERT
        depends on X86
index 285aab86c7ca142b449e22215732ca24463c515c..c5f171de0e1a0144247d653dcbd720c5f4ee5506 100644 (file)
@@ -7,5 +7,6 @@ obj-$(CONFIG_SPI_HISI_SFC)      += hisi-sfc.o
 obj-$(CONFIG_MTD_MT81xx_NOR)    += mtk-quadspi.o
 obj-$(CONFIG_SPI_NXP_SPIFI)    += nxp-spifi.o
 obj-$(CONFIG_SPI_INTEL_SPI)    += intel-spi.o
+obj-$(CONFIG_SPI_INTEL_SPI_PCI)        += intel-spi-pci.o
 obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM)   += intel-spi-platform.o
 obj-$(CONFIG_SPI_STM32_QUADSPI)        += stm32-quadspi.o
\ No newline at end of file
diff --git a/drivers/mtd/spi-nor/intel-spi-pci.c b/drivers/mtd/spi-nor/intel-spi-pci.c
new file mode 100644 (file)
index 0000000..e826523
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Intel PCH/PCU SPI flash PCI 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/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "intel-spi.h"
+
+#define BCR            0xdc
+#define BCR_WPD                BIT(0)
+
+static const struct intel_spi_boardinfo bxt_info = {
+       .type = INTEL_SPI_BXT,
+};
+
+static int intel_spi_pci_probe(struct pci_dev *pdev,
+                              const struct pci_device_id *id)
+{
+       struct intel_spi_boardinfo *info;
+       struct intel_spi *ispi;
+       u32 bcr;
+       int ret;
+
+       ret = pcim_enable_device(pdev);
+       if (ret)
+               return ret;
+
+       info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info),
+                           GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       /* Try to make the chip read/write */
+       pci_read_config_dword(pdev, BCR, &bcr);
+       if (!(bcr & BCR_WPD)) {
+               bcr |= BCR_WPD;
+               pci_write_config_dword(pdev, BCR, bcr);
+               pci_read_config_dword(pdev, BCR, &bcr);
+       }
+       info->writeable = !!(bcr & BCR_WPD);
+
+       ispi = intel_spi_probe(&pdev->dev, &pdev->resource[0], info);
+       if (IS_ERR(ispi))
+               return PTR_ERR(ispi);
+
+       pci_set_drvdata(pdev, ispi);
+       return 0;
+}
+
+static void intel_spi_pci_remove(struct pci_dev *pdev)
+{
+       intel_spi_remove(pci_get_drvdata(pdev));
+}
+
+static const struct pci_device_id intel_spi_pci_ids[] = {
+       { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
+       { },
+};
+MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids);
+
+static struct pci_driver intel_spi_pci_driver = {
+       .name = "intel-spi",
+       .id_table = intel_spi_pci_ids,
+       .probe = intel_spi_pci_probe,
+       .remove = intel_spi_pci_remove,
+};
+
+module_pci_driver(intel_spi_pci_driver);
+
+MODULE_DESCRIPTION("Intel PCH/PCU SPI flash PCI driver");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
+MODULE_LICENSE("GPL v2");