mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 14:12:06 +00:00
mtd: spi-nor / spi / MFD: Convert intel-spi to SPI MEM
Merge series from Mika Westerberg <mika.westerberg@linux.intel.com>:
Based on discussion on the patch I sent some time ago here:
http://lists.infradead.org/pipermail/linux-mtd/2021-June/086867.html
it turns out that the preferred way to deal with the SPI flash controller
drivers is through SPI MEM which is part of Linux SPI subsystem.
This series does that for the intel-spi driver. This also renames the
driver to follow the convention used in the SPI subsystem. The first patch
improves the write protection handling to be slightly more safer. The
following two patches do the conversion itself. Note the Intel SPI flash
controller only allows commands such as read, write and so on and it
internally uses whatever addressing etc. it figured from the SFDP on the
flash device.
base-commit: e783362eb5
This commit is contained in:
commit
0177212e27
@ -7,6 +7,6 @@ Memory Technology Device (MTD)
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
intel-spi
|
||||
spi-intel
|
||||
nand_ecc
|
||||
spi-nor
|
||||
|
@ -1,5 +1,5 @@
|
||||
==============================
|
||||
Upgrading BIOS using intel-spi
|
||||
Upgrading BIOS using spi-intel
|
||||
==============================
|
||||
|
||||
Many Intel CPUs like Baytrail and Braswell include SPI serial flash host
|
||||
@ -11,12 +11,12 @@ 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
|
||||
The spi-intel 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".
|
||||
passing "spi_intel.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
|
||||
@ -32,7 +32,7 @@ Linux.
|
||||
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
|
||||
3) Add "spi_intel.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).
|
||||
|
@ -63,6 +63,8 @@
|
||||
#define SPIBASE_BYT 0x54
|
||||
#define SPIBASE_BYT_SZ 512
|
||||
#define SPIBASE_BYT_EN BIT(1)
|
||||
#define BYT_BCR 0xfc
|
||||
#define BYT_BCR_WPD BIT(0)
|
||||
|
||||
#define SPIBASE_LPT 0x3800
|
||||
#define SPIBASE_LPT_SZ 512
|
||||
@ -1084,12 +1086,57 @@ wdt_done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool lpc_ich_byt_set_writeable(void __iomem *base, void *data)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(base + BYT_BCR);
|
||||
if (!(val & BYT_BCR_WPD)) {
|
||||
val |= BYT_BCR_WPD;
|
||||
writel(val, base + BYT_BCR);
|
||||
val = readl(base + BYT_BCR);
|
||||
}
|
||||
|
||||
return val & BYT_BCR_WPD;
|
||||
}
|
||||
|
||||
static bool lpc_ich_lpt_set_writeable(void __iomem *base, void *data)
|
||||
{
|
||||
struct pci_dev *pdev = data;
|
||||
u32 bcr;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return bcr & BCR_WPD;
|
||||
}
|
||||
|
||||
static bool lpc_ich_bxt_set_writeable(void __iomem *base, void *data)
|
||||
{
|
||||
unsigned int spi = PCI_DEVFN(13, 2);
|
||||
struct pci_bus *bus = data;
|
||||
u32 bcr;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return bcr & BCR_WPD;
|
||||
}
|
||||
|
||||
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;
|
||||
u32 spi_base, rcba;
|
||||
|
||||
info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
@ -1103,6 +1150,8 @@ static int lpc_ich_init_spi(struct pci_dev *dev)
|
||||
if (spi_base & SPIBASE_BYT_EN) {
|
||||
res->start = spi_base & ~(SPIBASE_BYT_SZ - 1);
|
||||
res->end = res->start + SPIBASE_BYT_SZ - 1;
|
||||
|
||||
info->set_writeable = lpc_ich_byt_set_writeable;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1113,8 +1162,8 @@ static int lpc_ich_init_spi(struct pci_dev *dev)
|
||||
res->start = spi_base + SPIBASE_LPT;
|
||||
res->end = res->start + SPIBASE_LPT_SZ - 1;
|
||||
|
||||
pci_read_config_dword(dev, BCR, &bcr);
|
||||
info->writeable = !!(bcr & BCR_WPD);
|
||||
info->set_writeable = lpc_ich_lpt_set_writeable;
|
||||
info->data = dev;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1135,8 +1184,8 @@ static int lpc_ich_init_spi(struct pci_dev *dev)
|
||||
res->start = spi_base & 0xfffffff0;
|
||||
res->end = res->start + SPIBASE_APL_SZ - 1;
|
||||
|
||||
pci_bus_read_config_dword(bus, spi, BCR, &bcr);
|
||||
info->writeable = !!(bcr & BCR_WPD);
|
||||
info->set_writeable = lpc_ich_bxt_set_writeable;
|
||||
info->data = bus;
|
||||
}
|
||||
|
||||
pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x1);
|
||||
|
@ -26,39 +26,3 @@ config SPI_NXP_SPIFI
|
||||
SPIFI is a specialized controller for connecting serial SPI
|
||||
Flash. Enable this option if you have a device with a SPIFI
|
||||
controller and want to access the Flash as a mtd device.
|
||||
|
||||
config SPI_INTEL_SPI
|
||||
tristate
|
||||
|
||||
config SPI_INTEL_SPI_PCI
|
||||
tristate "Intel PCH/PCU SPI flash PCI driver (DANGEROUS)"
|
||||
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 (DANGEROUS)"
|
||||
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.
|
||||
|
@ -2,6 +2,3 @@
|
||||
obj-$(CONFIG_SPI_ASPEED_SMC) += aspeed-smc.o
|
||||
obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.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
|
||||
|
@ -1,21 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Intel PCH/PCU SPI flash driver.
|
||||
*
|
||||
* Copyright (C) 2016, Intel Corporation
|
||||
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef INTEL_SPI_H
|
||||
#define INTEL_SPI_H
|
||||
|
||||
#include <linux/platform_data/x86/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 */
|
@ -427,6 +427,45 @@ config SPI_INGENIC
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called spi-ingenic.
|
||||
|
||||
config SPI_INTEL
|
||||
tristate
|
||||
|
||||
config SPI_INTEL_PCI
|
||||
tristate "Intel PCH/PCU SPI flash PCI driver (DANGEROUS)"
|
||||
depends on PCI
|
||||
depends on X86 || COMPILE_TEST
|
||||
depends on SPI_MEM
|
||||
select SPI_INTEL
|
||||
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 spi-intel-pci.
|
||||
|
||||
config SPI_INTEL_PLATFORM
|
||||
tristate "Intel PCH/PCU SPI flash platform driver (DANGEROUS)"
|
||||
depends on X86 || COMPILE_TEST
|
||||
depends on SPI_MEM
|
||||
select SPI_INTEL
|
||||
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 spi-intel-platform.
|
||||
|
||||
config SPI_JCORE
|
||||
tristate "J-Core SPI Master"
|
||||
depends on OF && (SUPERH || COMPILE_TEST)
|
||||
|
@ -61,6 +61,9 @@ obj-$(CONFIG_SPI_HISI_SFC_V3XX) += spi-hisi-sfc-v3xx.o
|
||||
obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o
|
||||
obj-$(CONFIG_SPI_IMX) += spi-imx.o
|
||||
obj-$(CONFIG_SPI_INGENIC) += spi-ingenic.o
|
||||
obj-$(CONFIG_SPI_INTEL) += spi-intel.o
|
||||
obj-$(CONFIG_SPI_INTEL_PCI) += spi-intel-pci.o
|
||||
obj-$(CONFIG_SPI_INTEL_PLATFORM) += spi-intel-platform.o
|
||||
obj-$(CONFIG_SPI_LANTIQ_SSC) += spi-lantiq-ssc.o
|
||||
obj-$(CONFIG_SPI_JCORE) += spi-jcore.o
|
||||
obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
|
||||
|
@ -2,34 +2,48 @@
|
||||
/*
|
||||
* Intel PCH/PCU SPI flash PCI driver.
|
||||
*
|
||||
* Copyright (C) 2016, Intel Corporation
|
||||
* Copyright (C) 2016 - 2022, Intel Corporation
|
||||
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "intel-spi.h"
|
||||
#include "spi-intel.h"
|
||||
|
||||
#define BCR 0xdc
|
||||
#define BCR_WPD BIT(0)
|
||||
|
||||
static bool intel_spi_pci_set_writeable(void __iomem *base, void *data)
|
||||
{
|
||||
struct pci_dev *pdev = data;
|
||||
u32 bcr;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
return bcr & BCR_WPD;
|
||||
}
|
||||
|
||||
static const struct intel_spi_boardinfo bxt_info = {
|
||||
.type = INTEL_SPI_BXT,
|
||||
.set_writeable = intel_spi_pci_set_writeable,
|
||||
};
|
||||
|
||||
static const struct intel_spi_boardinfo cnl_info = {
|
||||
.type = INTEL_SPI_CNL,
|
||||
.set_writeable = intel_spi_pci_set_writeable,
|
||||
};
|
||||
|
||||
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);
|
||||
@ -41,26 +55,8 @@ static int intel_spi_pci_probe(struct pci_dev *pdev,
|
||||
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));
|
||||
info->data = pdev;
|
||||
return intel_spi_probe(&pdev->dev, &pdev->resource[0], info);
|
||||
}
|
||||
|
||||
static const struct pci_device_id intel_spi_pci_ids[] = {
|
||||
@ -89,7 +85,6 @@ 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);
|
@ -2,20 +2,18 @@
|
||||
/*
|
||||
* Intel PCH/PCU SPI flash platform driver.
|
||||
*
|
||||
* Copyright (C) 2016, Intel Corporation
|
||||
* Copyright (C) 2016 - 2022, Intel Corporation
|
||||
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "intel-spi.h"
|
||||
#include "spi-intel.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);
|
||||
@ -23,24 +21,11 @@ static int intel_spi_platform_probe(struct platform_device *pdev)
|
||||
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);
|
||||
return intel_spi_probe(&pdev->dev, mem, info);
|
||||
}
|
||||
|
||||
static struct platform_driver intel_spi_platform_driver = {
|
||||
.probe = intel_spi_platform_probe,
|
||||
.remove = intel_spi_platform_remove,
|
||||
.driver = {
|
||||
.name = "intel-spi",
|
||||
},
|
File diff suppressed because it is too large
Load Diff
19
drivers/spi/spi-intel.h
Normal file
19
drivers/spi/spi-intel.h
Normal file
@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Intel PCH/PCU SPI flash driver.
|
||||
*
|
||||
* Copyright (C) 2016 - 2022, Intel Corporation
|
||||
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef SPI_INTEL_H
|
||||
#define SPI_INTEL_H
|
||||
|
||||
#include <linux/platform_data/x86/spi-intel.h>
|
||||
|
||||
struct resource;
|
||||
|
||||
int intel_spi_probe(struct device *dev, struct resource *mem,
|
||||
const struct intel_spi_boardinfo *info);
|
||||
|
||||
#endif /* SPI_INTEL_H */
|
@ -8,7 +8,7 @@
|
||||
#ifndef LPC_ICH_H
|
||||
#define LPC_ICH_H
|
||||
|
||||
#include <linux/platform_data/x86/intel-spi.h>
|
||||
#include <linux/platform_data/x86/spi-intel.h>
|
||||
|
||||
/* GPIO resources */
|
||||
#define ICH_RES_GPIO 0
|
||||
|
@ -6,8 +6,8 @@
|
||||
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef INTEL_SPI_PDATA_H
|
||||
#define INTEL_SPI_PDATA_H
|
||||
#ifndef SPI_INTEL_PDATA_H
|
||||
#define SPI_INTEL_PDATA_H
|
||||
|
||||
enum intel_spi_type {
|
||||
INTEL_SPI_BYT = 1,
|
||||
@ -19,11 +19,13 @@ enum intel_spi_type {
|
||||
/**
|
||||
* struct intel_spi_boardinfo - Board specific data for Intel SPI driver
|
||||
* @type: Type which this controller is compatible with
|
||||
* @writeable: The chip is writeable
|
||||
* @set_writeable: Try to make the chip writeable (optional)
|
||||
* @data: Data to be passed to @set_writeable can be %NULL
|
||||
*/
|
||||
struct intel_spi_boardinfo {
|
||||
enum intel_spi_type type;
|
||||
bool writeable;
|
||||
bool (*set_writeable)(void __iomem *base, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
#endif /* INTEL_SPI_PDATA_H */
|
||||
#endif /* SPI_INTEL_PDATA_H */
|
Loading…
Reference in New Issue
Block a user