mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:46:16 +00:00
b1258105f9
The manufacturing access to the PCH/SoC SPI device is traditionally performed via userspace driver accessing registers via /dev/mem but due to security concerns /dev/mem access is being much restricted, hence the reason for utilizing dedicated Intel PCH/SoC SPI controller driver, which is already implemented in the Linux kernel. Intel PCH/SoC SPI controller protects the flash storage via two mechanisms one is the via region protection registers and second via BIOS lock. The BIOS locks only the BIOS regions usually 0 and/or 6. The device always boots with BIOS lock set, but during manufacturing the BIOS lock has to be lifted in order to enable the write access. This can be done by passing "writeable=1" in the command line when the driver is loaded. This "locked" state is exposed through new sysfs attributes (intel_spi_locked, intel_spi_bios_locked). Second, also the region protection status is exposed via sysfs attribute (intel_spi_protected) as the manufacturing will need the both files in order to validate that the device is properly sealed. Includes code written by Tamar Mashiah. Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Co-developed-by: Tomas Winkler <tomasw@gmail.com> Signed-off-by: Tomas Winkler <tomasw@gmail.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Link: https://patch.msgid.link/20241009062244.2436793-1-mika.westerberg@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
105 lines
3.3 KiB
C
105 lines
3.3 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Intel PCH/PCU SPI flash PCI driver.
|
|
*
|
|
* Copyright (C) 2016 - 2022, Intel Corporation
|
|
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/pci.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;
|
|
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;
|
|
|
|
info->data = pdev;
|
|
return intel_spi_probe(&pdev->dev, &pdev->resource[0], info);
|
|
}
|
|
|
|
static const struct pci_device_id intel_spi_pci_ids[] = {
|
|
{ PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
|
|
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
|
|
{ PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info },
|
|
{ PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0x38a4), (unsigned long)&bxt_info },
|
|
{ PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
|
|
{ PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info },
|
|
{ PCI_VDEVICE(INTEL, 0x51a4), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0x54a4), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0x5794), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0x7e23), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0x7f24), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0x9d24), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0x9da4), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
|
|
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
|
|
{ PCI_VDEVICE(INTEL, 0xa2a4), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&cnl_info },
|
|
{ PCI_VDEVICE(INTEL, 0xa823), (unsigned long)&cnl_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,
|
|
.dev_groups = intel_spi_groups,
|
|
};
|
|
|
|
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");
|