All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] mtd: intel-spi: split read/write modes
@ 2021-09-10 21:13 Mauro Lima
  2021-09-10 21:13 ` [PATCH 1/4] mtd: intel-spi: rename intel-spi to intel-spi-base Mauro Lima
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Mauro Lima @ 2021-09-10 21:13 UTC (permalink / raw)
  To: linux-mtd
  Cc: daniel.gutson, richard, tudor.ambarus, miquel.raynal, richard,
	vigneshr, mika.westerberg, mauro.lima

The purpose of the following patchset is to split read/write
functionality from the Intel PCH/PCU SPI flash driver.
Being able to use the driver in read-only mode (harmless), the users
can get important firmware information from userspace which also
includes being able to perform firmware attestation to verify
integrity.

Currently fwupd is accessing to firmware information but only
with SecureBoot disabled. With this driver the fwupd project could
get such information with SecureBoot enabled.

Mauro Lima (4):
  mtd: intel-spi: rename intel-spi to intel-spi-base
  mtd: intel-spi: move chip internals into a defs.h
  mtd: intel-spi: moving write/erase functions
  mtd: intel-spi: add read only stubs

 drivers/mtd/spi-nor/controllers/Kconfig       |  50 +-
 drivers/mtd/spi-nor/controllers/Makefile      |   3 +
 .../{intel-spi.c => intel-spi-base.c}         | 442 ++----------------
 .../{intel-spi.h => intel-spi-base.h}         |   1 +
 .../mtd/spi-nor/controllers/intel-spi-defs.h  | 157 +++++++
 .../mtd/spi-nor/controllers/intel-spi-pci.c   |   2 +-
 .../spi-nor/controllers/intel-spi-platform.c  |   2 +-
 .../mtd/spi-nor/controllers/intel-spi-ro.c    |  50 ++
 .../mtd/spi-nor/controllers/intel-spi-rw.h    |  24 +
 drivers/mtd/spi-nor/controllers/intel-spi-w.c | 289 ++++++++++++
 include/linux/platform_data/x86/intel-spi.h   |   2 +
 11 files changed, 595 insertions(+), 427 deletions(-)
 rename drivers/mtd/spi-nor/controllers/{intel-spi.c => intel-spi-base.c} (54%)
 rename drivers/mtd/spi-nor/controllers/{intel-spi.h => intel-spi-base.h} (97%)
 create mode 100644 drivers/mtd/spi-nor/controllers/intel-spi-defs.h
 create mode 100644 drivers/mtd/spi-nor/controllers/intel-spi-ro.c
 create mode 100644 drivers/mtd/spi-nor/controllers/intel-spi-rw.h
 create mode 100644 drivers/mtd/spi-nor/controllers/intel-spi-w.c

-- 
2.31.1


-- 


This e-mail and any attachments may contain information that is 
privileged, confidential,  and/or exempt from disclosure under applicable 
law.  If you are not the intended recipient, you are hereby notified that 
any disclosure, copying, distribution or use of any information contained 
herein is strictly prohibited. If you have received this transmission in 
error, please immediately notify the sender and destroy the original 
transmission and any attachments, whether in electronic or hard copy 
format, without reading or saving.













______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/4] mtd: intel-spi: rename intel-spi to intel-spi-base
  2021-09-10 21:13 [PATCH 0/4] mtd: intel-spi: split read/write modes Mauro Lima
@ 2021-09-10 21:13 ` Mauro Lima
  2021-09-13 10:00   ` Mika Westerberg
  2021-09-10 21:13 ` [PATCH 2/4] mtd: intel-spi: move chip internals into a defs.h Mauro Lima
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Mauro Lima @ 2021-09-10 21:13 UTC (permalink / raw)
  To: linux-mtd
  Cc: daniel.gutson, richard, tudor.ambarus, miquel.raynal, richard,
	vigneshr, mika.westerberg, mauro.lima

Rename the files we want to split as base files.
Include the new files in intel-spi-{pci|platform}.c.
Change the intel-spi obj Makefile to be built with
intel-spi-base.

Suggested-by: Daniel Gutson <daniel.gutson@eclypsium.com>
Suggested-by: Richard Hughes <richard@hughsie.com>
Signed-off-by: Mauro Lima <mauro.lima@eclypsium.com>
---
 drivers/mtd/spi-nor/controllers/Makefile                        | 1 +
 .../mtd/spi-nor/controllers/{intel-spi.c => intel-spi-base.c}   | 2 +-
 .../mtd/spi-nor/controllers/{intel-spi.h => intel-spi-base.h}   | 0
 drivers/mtd/spi-nor/controllers/intel-spi-pci.c                 | 2 +-
 drivers/mtd/spi-nor/controllers/intel-spi-platform.c            | 2 +-
 5 files changed, 4 insertions(+), 3 deletions(-)
 rename drivers/mtd/spi-nor/controllers/{intel-spi.c => intel-spi-base.c} (99%)
 rename drivers/mtd/spi-nor/controllers/{intel-spi.h => intel-spi-base.h} (100%)

diff --git a/drivers/mtd/spi-nor/controllers/Makefile b/drivers/mtd/spi-nor/controllers/Makefile
index e7abba491d98..fa2dc480d2c8 100644
--- a/drivers/mtd/spi-nor/controllers/Makefile
+++ b/drivers/mtd/spi-nor/controllers/Makefile
@@ -3,5 +3,6 @@ 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
+intel-spi-y := intel-spi-base.o
 obj-$(CONFIG_SPI_INTEL_SPI_PCI)	+= intel-spi-pci.o
 obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM)	+= intel-spi-platform.o
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi.c b/drivers/mtd/spi-nor/controllers/intel-spi-base.c
similarity index 99%
rename from drivers/mtd/spi-nor/controllers/intel-spi.c
rename to drivers/mtd/spi-nor/controllers/intel-spi-base.c
index a413892ff449..362fb41b969e 100644
--- a/drivers/mtd/spi-nor/controllers/intel-spi.c
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-base.c
@@ -16,7 +16,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/spi-nor.h>
 
-#include "intel-spi.h"
+#include "intel-spi-base.h"
 
 /* Offsets are from @ispi->base */
 #define BFPREG				0x00
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi.h b/drivers/mtd/spi-nor/controllers/intel-spi-base.h
similarity index 100%
rename from drivers/mtd/spi-nor/controllers/intel-spi.h
rename to drivers/mtd/spi-nor/controllers/intel-spi-base.h
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c
index 1bc53b8bb88a..46db2743e244 100644
--- a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c
@@ -11,7 +11,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 
-#include "intel-spi.h"
+#include "intel-spi-base.h"
 
 #define BCR		0xdc
 #define BCR_WPD		BIT(0)
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-platform.c b/drivers/mtd/spi-nor/controllers/intel-spi-platform.c
index f80f1086f928..5d6b6125c4b5 100644
--- a/drivers/mtd/spi-nor/controllers/intel-spi-platform.c
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-platform.c
@@ -10,7 +10,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
-#include "intel-spi.h"
+#include "intel-spi-base.h"
 
 static int intel_spi_platform_probe(struct platform_device *pdev)
 {
-- 
2.31.1


-- 


This e-mail and any attachments may contain information that is 
privileged, confidential,  and/or exempt from disclosure under applicable 
law.  If you are not the intended recipient, you are hereby notified that 
any disclosure, copying, distribution or use of any information contained 
herein is strictly prohibited. If you have received this transmission in 
error, please immediately notify the sender and destroy the original 
transmission and any attachments, whether in electronic or hard copy 
format, without reading or saving.













______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/4] mtd: intel-spi: move chip internals into a defs.h
  2021-09-10 21:13 [PATCH 0/4] mtd: intel-spi: split read/write modes Mauro Lima
  2021-09-10 21:13 ` [PATCH 1/4] mtd: intel-spi: rename intel-spi to intel-spi-base Mauro Lima
@ 2021-09-10 21:13 ` Mauro Lima
  2021-09-10 21:13 ` [PATCH 3/4] mtd: intel-spi: moving write/erase functions Mauro Lima
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Mauro Lima @ 2021-09-10 21:13 UTC (permalink / raw)
  To: linux-mtd
  Cc: daniel.gutson, richard, tudor.ambarus, miquel.raynal, richard,
	vigneshr, mika.westerberg, mauro.lima

Move definitions about chip and internal spi structure to a defs
header file.
Add types.h to .../platform_data/x86/intel-spi.h so it doesn't
depends in the order of include files from intel-spi-base.
Forward declare struct device to be able to compile.

Suggested-by: Daniel Gutson <daniel.gutson@eclypsium.com>
Suggested-by: Richard Hughes <richard@hughsie.com>
Signed-off-by: Mauro Lima <mauro.lima@eclypsium.com>
---
 .../mtd/spi-nor/controllers/intel-spi-base.c  | 151 +----------------
 .../mtd/spi-nor/controllers/intel-spi-base.h  |   1 +
 .../mtd/spi-nor/controllers/intel-spi-defs.h  | 157 ++++++++++++++++++
 include/linux/platform_data/x86/intel-spi.h   |   2 +
 4 files changed, 161 insertions(+), 150 deletions(-)
 create mode 100644 drivers/mtd/spi-nor/controllers/intel-spi-defs.h

diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-base.c b/drivers/mtd/spi-nor/controllers/intel-spi-base.c
index 362fb41b969e..04ff1c381f1d 100644
--- a/drivers/mtd/spi-nor/controllers/intel-spi-base.c
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-base.c
@@ -6,157 +6,8 @@
  * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
  */
 
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/sizes.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/spi-nor.h>
-
 #include "intel-spi-base.h"
-
-/* Offsets are from @ispi->base */
-#define BFPREG				0x00
-
-#define HSFSTS_CTL			0x04
-#define HSFSTS_CTL_FSMIE		BIT(31)
-#define HSFSTS_CTL_FDBC_SHIFT		24
-#define HSFSTS_CTL_FDBC_MASK		(0x3f << HSFSTS_CTL_FDBC_SHIFT)
-
-#define HSFSTS_CTL_FCYCLE_SHIFT		17
-#define HSFSTS_CTL_FCYCLE_MASK		(0x0f << HSFSTS_CTL_FCYCLE_SHIFT)
-/* HW sequencer opcodes */
-#define HSFSTS_CTL_FCYCLE_READ		(0x00 << HSFSTS_CTL_FCYCLE_SHIFT)
-#define HSFSTS_CTL_FCYCLE_WRITE		(0x02 << HSFSTS_CTL_FCYCLE_SHIFT)
-#define HSFSTS_CTL_FCYCLE_ERASE		(0x03 << HSFSTS_CTL_FCYCLE_SHIFT)
-#define HSFSTS_CTL_FCYCLE_ERASE_64K	(0x04 << HSFSTS_CTL_FCYCLE_SHIFT)
-#define HSFSTS_CTL_FCYCLE_RDID		(0x06 << HSFSTS_CTL_FCYCLE_SHIFT)
-#define HSFSTS_CTL_FCYCLE_WRSR		(0x07 << HSFSTS_CTL_FCYCLE_SHIFT)
-#define HSFSTS_CTL_FCYCLE_RDSR		(0x08 << HSFSTS_CTL_FCYCLE_SHIFT)
-
-#define HSFSTS_CTL_FGO			BIT(16)
-#define HSFSTS_CTL_FLOCKDN		BIT(15)
-#define HSFSTS_CTL_FDV			BIT(14)
-#define HSFSTS_CTL_SCIP			BIT(5)
-#define HSFSTS_CTL_AEL			BIT(2)
-#define HSFSTS_CTL_FCERR		BIT(1)
-#define HSFSTS_CTL_FDONE		BIT(0)
-
-#define FADDR				0x08
-#define DLOCK				0x0c
-#define FDATA(n)			(0x10 + ((n) * 4))
-
-#define FRACC				0x50
-
-#define FREG(n)				(0x54 + ((n) * 4))
-#define FREG_BASE_MASK			0x3fff
-#define FREG_LIMIT_SHIFT		16
-#define FREG_LIMIT_MASK			(0x03fff << FREG_LIMIT_SHIFT)
-
-/* Offset is from @ispi->pregs */
-#define PR(n)				((n) * 4)
-#define PR_WPE				BIT(31)
-#define PR_LIMIT_SHIFT			16
-#define PR_LIMIT_MASK			(0x3fff << PR_LIMIT_SHIFT)
-#define PR_RPE				BIT(15)
-#define PR_BASE_MASK			0x3fff
-
-/* Offsets are from @ispi->sregs */
-#define SSFSTS_CTL			0x00
-#define SSFSTS_CTL_FSMIE		BIT(23)
-#define SSFSTS_CTL_DS			BIT(22)
-#define SSFSTS_CTL_DBC_SHIFT		16
-#define SSFSTS_CTL_SPOP			BIT(11)
-#define SSFSTS_CTL_ACS			BIT(10)
-#define SSFSTS_CTL_SCGO			BIT(9)
-#define SSFSTS_CTL_COP_SHIFT		12
-#define SSFSTS_CTL_FRS			BIT(7)
-#define SSFSTS_CTL_DOFRS		BIT(6)
-#define SSFSTS_CTL_AEL			BIT(4)
-#define SSFSTS_CTL_FCERR		BIT(3)
-#define SSFSTS_CTL_FDONE		BIT(2)
-#define SSFSTS_CTL_SCIP			BIT(0)
-
-#define PREOP_OPTYPE			0x04
-#define OPMENU0				0x08
-#define OPMENU1				0x0c
-
-#define OPTYPE_READ_NO_ADDR		0
-#define OPTYPE_WRITE_NO_ADDR		1
-#define OPTYPE_READ_WITH_ADDR		2
-#define OPTYPE_WRITE_WITH_ADDR		3
-
-/* CPU specifics */
-#define BYT_PR				0x74
-#define BYT_SSFSTS_CTL			0x90
-#define BYT_BCR				0xfc
-#define BYT_BCR_WPD			BIT(0)
-#define BYT_FREG_NUM			5
-#define BYT_PR_NUM			5
-
-#define LPT_PR				0x74
-#define LPT_SSFSTS_CTL			0x90
-#define LPT_FREG_NUM			5
-#define LPT_PR_NUM			5
-
-#define BXT_PR				0x84
-#define BXT_SSFSTS_CTL			0xa0
-#define BXT_FREG_NUM			12
-#define BXT_PR_NUM			6
-
-#define CNL_PR				0x84
-#define CNL_FREG_NUM			6
-#define CNL_PR_NUM			5
-
-#define LVSCC				0xc4
-#define UVSCC				0xc8
-#define ERASE_OPCODE_SHIFT		8
-#define ERASE_OPCODE_MASK		(0xff << ERASE_OPCODE_SHIFT)
-#define ERASE_64K_OPCODE_SHIFT		16
-#define ERASE_64K_OPCODE_MASK		(0xff << ERASE_OPCODE_SHIFT)
-
-#define INTEL_SPI_TIMEOUT		5000 /* ms */
-#define INTEL_SPI_FIFO_SZ		64
-
-/**
- * struct intel_spi - Driver private data
- * @dev: Device pointer
- * @info: Pointer to board specific info
- * @nor: SPI NOR layer structure
- * @base: Beginning of MMIO space
- * @pregs: Start of protection registers
- * @sregs: Start of software sequencer registers
- * @nregions: Maximum number of regions
- * @pr_num: Maximum number of protected range registers
- * @writeable: Is the chip writeable
- * @locked: Is SPI setting locked
- * @swseq_reg: Use SW sequencer in register reads/writes
- * @swseq_erase: Use SW sequencer in erase operation
- * @erase_64k: 64k erase supported
- * @atomic_preopcode: Holds preopcode when atomic sequence is requested
- * @opcodes: Opcodes which are supported. This are programmed by BIOS
- *           before it locks down the controller.
- */
-struct intel_spi {
-	struct device *dev;
-	const struct intel_spi_boardinfo *info;
-	struct spi_nor nor;
-	void __iomem *base;
-	void __iomem *pregs;
-	void __iomem *sregs;
-	size_t nregions;
-	size_t pr_num;
-	bool writeable;
-	bool locked;
-	bool swseq_reg;
-	bool swseq_erase;
-	bool erase_64k;
-	u8 atomic_preopcode;
-	u8 opcodes[8];
-};
+#include "intel-spi-defs.h"
 
 static bool writeable;
 module_param(writeable, bool, 0);
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-base.h b/drivers/mtd/spi-nor/controllers/intel-spi-base.h
index f2871179fd34..ac01c0756888 100644
--- a/drivers/mtd/spi-nor/controllers/intel-spi-base.h
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-base.h
@@ -11,6 +11,7 @@
 
 #include <linux/platform_data/x86/intel-spi.h>
 
+struct device;
 struct intel_spi;
 struct resource;
 
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-defs.h b/drivers/mtd/spi-nor/controllers/intel-spi-defs.h
new file mode 100644
index 000000000000..89da3f38fdbe
--- /dev/null
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-defs.h
@@ -0,0 +1,157 @@
+/* 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>
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/sizes.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spi-nor.h>
+
+/* Offsets are from @ispi->base */
+#define BFPREG				0x00
+
+#define HSFSTS_CTL			0x04
+#define HSFSTS_CTL_FSMIE		BIT(31)
+#define HSFSTS_CTL_FDBC_SHIFT		24
+#define HSFSTS_CTL_FDBC_MASK		(0x3f << HSFSTS_CTL_FDBC_SHIFT)
+
+#define HSFSTS_CTL_FCYCLE_SHIFT		17
+#define HSFSTS_CTL_FCYCLE_MASK		(0x0f << HSFSTS_CTL_FCYCLE_SHIFT)
+/* HW sequencer opcodes */
+#define HSFSTS_CTL_FCYCLE_READ		(0x00 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_WRITE		(0x02 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_ERASE		(0x03 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_ERASE_64K	(0x04 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_RDID		(0x06 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_WRSR		(0x07 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_RDSR		(0x08 << HSFSTS_CTL_FCYCLE_SHIFT)
+
+#define HSFSTS_CTL_FGO			BIT(16)
+#define HSFSTS_CTL_FLOCKDN		BIT(15)
+#define HSFSTS_CTL_FDV			BIT(14)
+#define HSFSTS_CTL_SCIP			BIT(5)
+#define HSFSTS_CTL_AEL			BIT(2)
+#define HSFSTS_CTL_FCERR		BIT(1)
+#define HSFSTS_CTL_FDONE		BIT(0)
+
+#define FADDR				0x08
+#define DLOCK				0x0c
+#define FDATA(n)			(0x10 + ((n) * 4))
+
+#define FRACC				0x50
+
+#define FREG(n)				(0x54 + ((n) * 4))
+#define FREG_BASE_MASK			0x3fff
+#define FREG_LIMIT_SHIFT		16
+#define FREG_LIMIT_MASK			(0x03fff << FREG_LIMIT_SHIFT)
+
+/* Offset is from @ispi->pregs */
+#define PR(n)				((n) * 4)
+#define PR_WPE				BIT(31)
+#define PR_LIMIT_SHIFT			16
+#define PR_LIMIT_MASK			(0x3fff << PR_LIMIT_SHIFT)
+#define PR_RPE				BIT(15)
+#define PR_BASE_MASK			0x3fff
+
+/* Offsets are from @ispi->sregs */
+#define SSFSTS_CTL			0x00
+#define SSFSTS_CTL_FSMIE		BIT(23)
+#define SSFSTS_CTL_DS			BIT(22)
+#define SSFSTS_CTL_DBC_SHIFT		16
+#define SSFSTS_CTL_SPOP			BIT(11)
+#define SSFSTS_CTL_ACS			BIT(10)
+#define SSFSTS_CTL_SCGO			BIT(9)
+#define SSFSTS_CTL_COP_SHIFT		12
+#define SSFSTS_CTL_FRS			BIT(7)
+#define SSFSTS_CTL_DOFRS		BIT(6)
+#define SSFSTS_CTL_AEL			BIT(4)
+#define SSFSTS_CTL_FCERR		BIT(3)
+#define SSFSTS_CTL_FDONE		BIT(2)
+#define SSFSTS_CTL_SCIP			BIT(0)
+
+#define PREOP_OPTYPE			0x04
+#define OPMENU0				0x08
+#define OPMENU1				0x0c
+
+#define OPTYPE_READ_NO_ADDR		0
+#define OPTYPE_WRITE_NO_ADDR		1
+#define OPTYPE_READ_WITH_ADDR		2
+#define OPTYPE_WRITE_WITH_ADDR		3
+
+/* CPU specifics */
+#define BYT_PR				0x74
+#define BYT_SSFSTS_CTL			0x90
+#define BYT_BCR				0xfc
+#define BYT_BCR_WPD			BIT(0)
+#define BYT_FREG_NUM			5
+#define BYT_PR_NUM			5
+
+#define LPT_PR				0x74
+#define LPT_SSFSTS_CTL			0x90
+#define LPT_FREG_NUM			5
+#define LPT_PR_NUM			5
+
+#define BXT_PR				0x84
+#define BXT_SSFSTS_CTL			0xa0
+#define BXT_FREG_NUM			12
+#define BXT_PR_NUM			6
+
+#define CNL_PR				0x84
+#define CNL_FREG_NUM			6
+#define CNL_PR_NUM			5
+
+#define LVSCC				0xc4
+#define UVSCC				0xc8
+#define ERASE_OPCODE_SHIFT		8
+#define ERASE_OPCODE_MASK		(0xff << ERASE_OPCODE_SHIFT)
+#define ERASE_64K_OPCODE_SHIFT		16
+#define ERASE_64K_OPCODE_MASK		(0xff << ERASE_OPCODE_SHIFT)
+
+#define INTEL_SPI_TIMEOUT		5000 /* ms */
+#define INTEL_SPI_FIFO_SZ		64
+
+/**
+ * struct intel_spi - Driver private data
+ * @dev: Device pointer
+ * @info: Pointer to board specific info
+ * @nor: SPI NOR layer structure
+ * @base: Beginning of MMIO space
+ * @pregs: Start of protection registers
+ * @sregs: Start of software sequencer registers
+ * @nregions: Maximum number of regions
+ * @pr_num: Maximum number of protected range registers
+ * @writeable: Is the chip writeable
+ * @locked: Is SPI setting locked
+ * @swseq_reg: Use SW sequencer in register reads/writes
+ * @swseq_erase: Use SW sequencer in erase operation
+ * @erase_64k: 64k erase supported
+ * @atomic_preopcode: Holds preopcode when atomic sequence is requested
+ * @opcodes: Opcodes which are supported. This are programmed by BIOS
+ *           before it locks down the controller.
+ */
+struct intel_spi {
+	struct device *dev;
+	const struct intel_spi_boardinfo *info;
+	struct spi_nor nor;
+	void __iomem *base;
+	void __iomem *pregs;
+	void __iomem *sregs;
+	size_t nregions;
+	size_t pr_num;
+	bool writeable;
+	bool locked;
+	bool swseq_reg;
+	bool swseq_erase;
+	bool erase_64k;
+	u8 atomic_preopcode;
+	u8 opcodes[8];
+};
diff --git a/include/linux/platform_data/x86/intel-spi.h b/include/linux/platform_data/x86/intel-spi.h
index 7f53a5c6f35e..4092a104f266 100644
--- a/include/linux/platform_data/x86/intel-spi.h
+++ b/include/linux/platform_data/x86/intel-spi.h
@@ -9,6 +9,8 @@
 #ifndef INTEL_SPI_PDATA_H
 #define INTEL_SPI_PDATA_H
 
+#include <linux/types.h>
+
 enum intel_spi_type {
 	INTEL_SPI_BYT = 1,
 	INTEL_SPI_LPT,
-- 
2.31.1


-- 


This e-mail and any attachments may contain information that is 
privileged, confidential,  and/or exempt from disclosure under applicable 
law.  If you are not the intended recipient, you are hereby notified that 
any disclosure, copying, distribution or use of any information contained 
herein is strictly prohibited. If you have received this transmission in 
error, please immediately notify the sender and destroy the original 
transmission and any attachments, whether in electronic or hard copy 
format, without reading or saving.













______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/4] mtd: intel-spi: moving write/erase functions
  2021-09-10 21:13 [PATCH 0/4] mtd: intel-spi: split read/write modes Mauro Lima
  2021-09-10 21:13 ` [PATCH 1/4] mtd: intel-spi: rename intel-spi to intel-spi-base Mauro Lima
  2021-09-10 21:13 ` [PATCH 2/4] mtd: intel-spi: move chip internals into a defs.h Mauro Lima
@ 2021-09-10 21:13 ` Mauro Lima
  2021-09-10 21:13 ` [PATCH 4/4] mtd: intel-spi: add read only stubs Mauro Lima
  2021-09-13  9:59 ` [PATCH 0/4] mtd: intel-spi: split read/write modes Mika Westerberg
  4 siblings, 0 replies; 8+ messages in thread
From: Mauro Lima @ 2021-09-10 21:13 UTC (permalink / raw)
  To: linux-mtd
  Cc: daniel.gutson, richard, tudor.ambarus, miquel.raynal, richard,
	vigneshr, mika.westerberg, mauro.lima

Split the write/erase behavior. In order to avoid code duplication,
we are going to move all the write/erase functionality to a new
file 'intel-spi-w.c' and left the base file as a common place for
both write and read only ops.
Change the make of intel-spi so we don't have to export
all the symbols used between 'intel-spi-w' and 'intel-spi-base'.
Add MODULE_LICENSE() to be able to compile as M.
Remove the module param flag, this will be set through menuconfig.

This is the new include diagram:

                    +--------------------+
                    |/include/intel-spi.h|
                    +--------^-----------+
                             |
                             |                  intel-spi-defs.h
                             |                         ^
                             |                         |
{pci|platform} -----> intel-spi-base.h          intel-spi-rw.h
                              ^                 ^       ^
                              |       +---------+       |
                              |       |                 |
                              |       |                 |
                              |       |                 |
                        intel-spi-base.c         intel-spi-w.c

Suggested-by: Daniel Gutson <daniel.gutson@eclypsium.com>
Suggested-by: Richard Hughes <richard@hughsie.com>
Signed-off-by: Mauro Lima <mauro.lima@eclypsium.com>
---
 drivers/mtd/spi-nor/controllers/Makefile      |   2 +-
 .../mtd/spi-nor/controllers/intel-spi-base.c  | 291 ++----------------
 .../mtd/spi-nor/controllers/intel-spi-rw.h    |  23 ++
 drivers/mtd/spi-nor/controllers/intel-spi-w.c | 289 +++++++++++++++++
 4 files changed, 345 insertions(+), 260 deletions(-)
 create mode 100644 drivers/mtd/spi-nor/controllers/intel-spi-rw.h
 create mode 100644 drivers/mtd/spi-nor/controllers/intel-spi-w.c

diff --git a/drivers/mtd/spi-nor/controllers/Makefile b/drivers/mtd/spi-nor/controllers/Makefile
index fa2dc480d2c8..1933a7c2c30b 100644
--- a/drivers/mtd/spi-nor/controllers/Makefile
+++ b/drivers/mtd/spi-nor/controllers/Makefile
@@ -3,6 +3,6 @@ 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
-intel-spi-y := intel-spi-base.o
+intel-spi-y := intel-spi-base.o intel-spi-w.o
 obj-$(CONFIG_SPI_INTEL_SPI_PCI)	+= intel-spi-pci.o
 obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM)	+= intel-spi-platform.o
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-base.c b/drivers/mtd/spi-nor/controllers/intel-spi-base.c
index 04ff1c381f1d..7cb5109ad0d4 100644
--- a/drivers/mtd/spi-nor/controllers/intel-spi-base.c
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-base.c
@@ -7,11 +7,8 @@
  */
 
 #include "intel-spi-base.h"
-#include "intel-spi-defs.h"
 
-static bool writeable;
-module_param(writeable, bool, 0);
-MODULE_PARM_DESC(writeable, "Enable write access to SPI flash chip (default=0)");
+#include "intel-spi-rw.h"
 
 static void intel_spi_dump_regs(struct intel_spi *ispi)
 {
@@ -116,28 +113,7 @@ static int intel_spi_read_block(struct intel_spi *ispi, void *buf, size_t size)
 	return 0;
 }
 
-/* Writes max INTEL_SPI_FIFO_SZ bytes to the device fifo */
-static int intel_spi_write_block(struct intel_spi *ispi, const void *buf,
-				 size_t size)
-{
-	size_t bytes;
-	int i = 0;
-
-	if (size > INTEL_SPI_FIFO_SZ)
-		return -EINVAL;
-
-	while (size > 0) {
-		bytes = min_t(size_t, size, 4);
-		memcpy_toio(ispi->base + FDATA(i), buf, bytes);
-		size -= bytes;
-		buf += bytes;
-		i++;
-	}
-
-	return 0;
-}
-
-static int intel_spi_wait_hw_busy(struct intel_spi *ispi)
+int intel_spi_wait_hw_busy(struct intel_spi *ispi)
 {
 	u32 val;
 
@@ -157,8 +133,8 @@ static int intel_spi_wait_sw_busy(struct intel_spi *ispi)
 
 static int intel_spi_init(struct intel_spi *ispi)
 {
-	u32 opmenu0, opmenu1, lvscc, uvscc, val;
-	int i;
+	u32 opmenu0, opmenu1, val;
+	int i, ret;
 
 	switch (ispi->info->type) {
 	case INTEL_SPI_BYT:
@@ -168,17 +144,7 @@ static int intel_spi_init(struct intel_spi *ispi)
 		ispi->pr_num = BYT_PR_NUM;
 		ispi->swseq_reg = true;
 
-		if (writeable) {
-			/* Disable write protection */
-			val = readl(ispi->base + BYT_BCR);
-			if (!(val & BYT_BCR_WPD)) {
-				val |= BYT_BCR_WPD;
-				writel(val, ispi->base + BYT_BCR);
-				val = readl(ispi->base + BYT_BCR);
-			}
-
-			ispi->writeable = !!(val & BYT_BCR_WPD);
-		}
+		__intel_byt_rw_config(ispi);
 
 		break;
 
@@ -195,7 +161,9 @@ static int intel_spi_init(struct intel_spi *ispi)
 		ispi->pregs = ispi->base + BXT_PR;
 		ispi->nregions = BXT_FREG_NUM;
 		ispi->pr_num = BXT_PR_NUM;
-		ispi->erase_64k = true;
+
+		__intel_bxt_rw_config(ispi);
+
 		break;
 
 	case INTEL_SPI_CNL:
@@ -214,28 +182,9 @@ static int intel_spi_init(struct intel_spi *ispi)
 	val &= ~HSFSTS_CTL_FSMIE;
 	writel(val, ispi->base + HSFSTS_CTL);
 
-	/*
-	 * Determine whether erase operation should use HW or SW sequencer.
-	 *
-	 * The HW sequencer has a predefined list of opcodes, with only the
-	 * erase opcode being programmable in LVSCC and UVSCC registers.
-	 * If these registers don't contain a valid erase opcode, erase
-	 * cannot be done using HW sequencer.
-	 */
-	lvscc = readl(ispi->base + LVSCC);
-	uvscc = readl(ispi->base + UVSCC);
-	if (!(lvscc & ERASE_OPCODE_MASK) || !(uvscc & ERASE_OPCODE_MASK))
-		ispi->swseq_erase = true;
-	/* SPI controller on Intel BXT supports 64K erase opcode */
-	if (ispi->info->type == INTEL_SPI_BXT && !ispi->swseq_erase)
-		if (!(lvscc & ERASE_64K_OPCODE_MASK) ||
-		    !(uvscc & ERASE_64K_OPCODE_MASK))
-			ispi->erase_64k = false;
-
-	if (ispi->sregs == NULL && (ispi->swseq_reg || ispi->swseq_erase)) {
-		dev_err(ispi->dev, "software sequencer not supported, but required\n");
-		return -EINVAL;
-	}
+	ret = __configure_lvscc_uvscc(ispi);
+	if (ret < 0)
+		return ret;
 
 	/*
 	 * Some controllers can only do basic operations using hardware
@@ -296,7 +245,7 @@ static int intel_spi_opcode_index(struct intel_spi *ispi, u8 opcode, int optype)
 	return 0;
 }
 
-static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len)
+int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len)
 {
 	u32 val, status;
 	int ret;
@@ -309,7 +258,10 @@ static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len)
 		val |= HSFSTS_CTL_FCYCLE_RDID;
 		break;
 	case SPINOR_OP_WRSR:
-		val |= HSFSTS_CTL_FCYCLE_WRSR;
+		if (is_write_enabled())
+			val |= HSFSTS_CTL_FCYCLE_WRSR;
+		else
+			return -EINVAL;
 		break;
 	case SPINOR_OP_RDSR:
 		val |= HSFSTS_CTL_FCYCLE_RDSR;
@@ -339,8 +291,8 @@ static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len)
 	return 0;
 }
 
-static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len,
-			      int optype)
+int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len,
+		       int optype)
 {
 	u32 val = 0, status;
 	u8 atomic_preopcode;
@@ -367,29 +319,12 @@ static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len,
 	val |= SSFSTS_CTL_FCERR | SSFSTS_CTL_FDONE;
 	val |= SSFSTS_CTL_SCGO;
 	if (atomic_preopcode) {
-		u16 preop;
-
-		switch (optype) {
-		case OPTYPE_WRITE_NO_ADDR:
-		case OPTYPE_WRITE_WITH_ADDR:
-			/* Pick matching preopcode for the atomic sequence */
-			preop = readw(ispi->sregs + PREOP_OPTYPE);
-			if ((preop & 0xff) == atomic_preopcode)
-				; /* Do nothing */
-			else if ((preop >> 8) == atomic_preopcode)
-				val |= SSFSTS_CTL_SPOP;
-			else
-				return -EINVAL;
-
-			/* Enable atomic sequence */
-			val |= SSFSTS_CTL_ACS;
-			break;
-
-		default:
-			return -EINVAL;
-		}
-
+		ret = __intel_sw_cycle_write(ispi, optype, atomic_preopcode);
+		if (ret < 0)
+			return ret;
+		val |= ret;
 	}
+
 	writel(val, ispi->sregs + SSFSTS_CTL);
 
 	ret = intel_spi_wait_sw_busy(ispi);
@@ -429,59 +364,7 @@ static int intel_spi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
 static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf,
 			       size_t len)
 {
-	struct intel_spi *ispi = nor->priv;
-	int ret;
-
-	/*
-	 * This is handled with atomic operation and preop code in Intel
-	 * controller so we only verify that it is available. If the
-	 * controller is not locked, program the opcode to the PREOP
-	 * register for later use.
-	 *
-	 * When hardware sequencer is used there is no need to program
-	 * any opcodes (it handles them automatically as part of a command).
-	 */
-	if (opcode == SPINOR_OP_WREN) {
-		u16 preop;
-
-		if (!ispi->swseq_reg)
-			return 0;
-
-		preop = readw(ispi->sregs + PREOP_OPTYPE);
-		if ((preop & 0xff) != opcode && (preop >> 8) != opcode) {
-			if (ispi->locked)
-				return -EINVAL;
-			writel(opcode, ispi->sregs + PREOP_OPTYPE);
-		}
-
-		/*
-		 * This enables atomic sequence on next SW sycle. Will
-		 * be cleared after next operation.
-		 */
-		ispi->atomic_preopcode = opcode;
-		return 0;
-	}
-
-	/*
-	 * We hope that HW sequencer will do the right thing automatically and
-	 * with the SW sequencer we cannot use preopcode anyway, so just ignore
-	 * the Write Disable operation and pretend it was completed
-	 * successfully.
-	 */
-	if (opcode == SPINOR_OP_WRDI)
-		return 0;
-
-	writel(0, ispi->base + FADDR);
-
-	/* Write the value beforehand */
-	ret = intel_spi_write_block(ispi, buf, len);
-	if (ret)
-		return ret;
-
-	if (ispi->swseq_reg)
-		return intel_spi_sw_cycle(ispi, opcode, len,
-					  OPTYPE_WRITE_NO_ADDR);
-	return intel_spi_hw_cycle(ispi, opcode, len);
+	return __intel_spi_write_reg(nor, opcode, buf, len);
 }
 
 static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len,
@@ -558,126 +441,12 @@ static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len,
 static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len,
 			       const u_char *write_buf)
 {
-	struct intel_spi *ispi = nor->priv;
-	size_t block_size, retlen = 0;
-	u32 val, status;
-	ssize_t ret;
-
-	/* Not needed with HW sequencer write, make sure it is cleared */
-	ispi->atomic_preopcode = 0;
-
-	while (len > 0) {
-		block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ);
-
-		/* Write cannot cross 4K boundary */
-		block_size = min_t(loff_t, to + block_size,
-				   round_up(to + 1, SZ_4K)) - to;
-
-		writel(to, ispi->base + FADDR);
-
-		val = readl(ispi->base + HSFSTS_CTL);
-		val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK);
-		val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE;
-		val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT;
-		val |= HSFSTS_CTL_FCYCLE_WRITE;
-
-		ret = intel_spi_write_block(ispi, write_buf, block_size);
-		if (ret) {
-			dev_err(ispi->dev, "failed to write block\n");
-			return ret;
-		}
-
-		/* Start the write now */
-		val |= HSFSTS_CTL_FGO;
-		writel(val, ispi->base + HSFSTS_CTL);
-
-		ret = intel_spi_wait_hw_busy(ispi);
-		if (ret) {
-			dev_err(ispi->dev, "timeout\n");
-			return ret;
-		}
-
-		status = readl(ispi->base + HSFSTS_CTL);
-		if (status & HSFSTS_CTL_FCERR)
-			ret = -EIO;
-		else if (status & HSFSTS_CTL_AEL)
-			ret = -EACCES;
-
-		if (ret < 0) {
-			dev_err(ispi->dev, "write error: %llx: %#x\n", to,
-				status);
-			return ret;
-		}
-
-		len -= block_size;
-		to += block_size;
-		retlen += block_size;
-		write_buf += block_size;
-	}
-
-	return retlen;
+	return __intel_spi_write(nor, to, len, write_buf);
 }
 
 static int intel_spi_erase(struct spi_nor *nor, loff_t offs)
 {
-	size_t erase_size, len = nor->mtd.erasesize;
-	struct intel_spi *ispi = nor->priv;
-	u32 val, status, cmd;
-	int ret;
-
-	/* If the hardware can do 64k erase use that when possible */
-	if (len >= SZ_64K && ispi->erase_64k) {
-		cmd = HSFSTS_CTL_FCYCLE_ERASE_64K;
-		erase_size = SZ_64K;
-	} else {
-		cmd = HSFSTS_CTL_FCYCLE_ERASE;
-		erase_size = SZ_4K;
-	}
-
-	if (ispi->swseq_erase) {
-		while (len > 0) {
-			writel(offs, ispi->base + FADDR);
-
-			ret = intel_spi_sw_cycle(ispi, nor->erase_opcode,
-						 0, OPTYPE_WRITE_WITH_ADDR);
-			if (ret)
-				return ret;
-
-			offs += erase_size;
-			len -= erase_size;
-		}
-
-		return 0;
-	}
-
-	/* Not needed with HW sequencer erase, make sure it is cleared */
-	ispi->atomic_preopcode = 0;
-
-	while (len > 0) {
-		writel(offs, ispi->base + FADDR);
-
-		val = readl(ispi->base + HSFSTS_CTL);
-		val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK);
-		val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE;
-		val |= cmd;
-		val |= HSFSTS_CTL_FGO;
-		writel(val, ispi->base + HSFSTS_CTL);
-
-		ret = intel_spi_wait_hw_busy(ispi);
-		if (ret)
-			return ret;
-
-		status = readl(ispi->base + HSFSTS_CTL);
-		if (status & HSFSTS_CTL_FCERR)
-			return -EIO;
-		else if (status & HSFSTS_CTL_AEL)
-			return -EACCES;
-
-		offs += erase_size;
-		len -= erase_size;
-	}
-
-	return 0;
+	return __intel_spi_erase(nor, offs);
 }
 
 static bool intel_spi_is_protected(const struct intel_spi *ispi,
@@ -778,7 +547,11 @@ struct intel_spi *intel_spi_probe(struct device *dev,
 
 	ispi->dev = dev;
 	ispi->info = info;
-	ispi->writeable = info->writeable;
+
+	if (is_write_enabled())
+		ispi->writeable = info->writeable;
+	else
+		ispi->writeable = false;
 
 	ret = intel_spi_init(ispi);
 	if (ret)
@@ -797,7 +570,7 @@ struct intel_spi *intel_spi_probe(struct device *dev,
 	intel_spi_fill_partition(ispi, &part);
 
 	/* Prevent writes if not explicitly enabled */
-	if (!ispi->writeable || !writeable)
+	if (!ispi->writeable || !is_write_enabled())
 		ispi->nor.mtd.flags &= ~MTD_WRITEABLE;
 
 	ret = mtd_device_register(&ispi->nor.mtd, &part, 1);
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-rw.h b/drivers/mtd/spi-nor/controllers/intel-spi-rw.h
new file mode 100644
index 000000000000..46c6461a8a7b
--- /dev/null
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-rw.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef INTEL_SPI_RW_H
+#define INTEL_SPI_RW_H
+
+#include "intel-spi-defs.h"
+
+#include <linux/platform_data/x86/intel-spi.h>
+
+int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len, int optype);
+int intel_spi_wait_hw_busy(struct intel_spi *ispi);
+int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len);
+
+bool is_write_enabled(void);
+int  __intel_spi_erase(struct spi_nor *nor, loff_t offs);
+ssize_t  __intel_spi_write(struct spi_nor *nor, loff_t to, size_t len, const u_char *write_buf);
+int  __intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf,
+			   size_t len);
+int  __configure_lvscc_uvscc(struct intel_spi *ispi);
+int  __intel_sw_cycle_write(struct intel_spi *ispi, int optype, u8 atomic_preopcode);
+void  __intel_bxt_rw_config(struct intel_spi *ispi);
+void  __intel_byt_rw_config(struct intel_spi *ispi);
+
+#endif /* INTEL_SPI_RW_H */
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-w.c b/drivers/mtd/spi-nor/controllers/intel-spi-w.c
new file mode 100644
index 000000000000..ffe940611b57
--- /dev/null
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-w.c
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "intel-spi-rw.h"
+
+bool is_write_enabled(void)
+{
+	return true;
+}
+
+/* Writes max INTEL_SPI_FIFO_SZ bytes to the device fifo */
+static int intel_spi_write_block(struct intel_spi *ispi, const void *buf,
+				 size_t size)
+{
+	size_t bytes;
+	int i = 0;
+
+	if (size > INTEL_SPI_FIFO_SZ)
+		return -EINVAL;
+
+	while (size > 0) {
+		bytes = min_t(size_t, size, 4);
+		memcpy_toio(ispi->base + FDATA(i), buf, bytes);
+		size -= bytes;
+		buf += bytes;
+		i++;
+	}
+
+	return 0;
+}
+
+int __intel_spi_erase(struct spi_nor *nor, loff_t offs)
+{
+	size_t erase_size, len = nor->mtd.erasesize;
+	struct intel_spi *ispi = nor->priv;
+	u32 val, status, cmd;
+	int ret;
+
+	/* If the hardware can do 64k erase use that when possible */
+	if (len >= SZ_64K && ispi->erase_64k) {
+		cmd = HSFSTS_CTL_FCYCLE_ERASE_64K;
+		erase_size = SZ_64K;
+	} else {
+		cmd = HSFSTS_CTL_FCYCLE_ERASE;
+		erase_size = SZ_4K;
+	}
+
+	if (ispi->swseq_erase) {
+		while (len > 0) {
+			writel(offs, ispi->base + FADDR);
+
+			ret = intel_spi_sw_cycle(ispi, nor->erase_opcode,
+						 0, OPTYPE_WRITE_WITH_ADDR);
+			if (ret)
+				return ret;
+
+			offs += erase_size;
+			len -= erase_size;
+		}
+
+		return 0;
+	}
+
+	/* Not needed with HW sequencer erase, make sure it is cleared */
+	ispi->atomic_preopcode = 0;
+
+	while (len > 0) {
+		writel(offs, ispi->base + FADDR);
+
+		val = readl(ispi->base + HSFSTS_CTL);
+		val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK);
+		val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE;
+		val |= cmd;
+		val |= HSFSTS_CTL_FGO;
+		writel(val, ispi->base + HSFSTS_CTL);
+
+		ret = intel_spi_wait_hw_busy(ispi);
+		if (ret)
+			return ret;
+
+		status = readl(ispi->base + HSFSTS_CTL);
+		if (status & HSFSTS_CTL_FCERR)
+			return -EIO;
+		else if (status & HSFSTS_CTL_AEL)
+			return -EACCES;
+
+		offs += erase_size;
+		len -= erase_size;
+	}
+
+	return 0;
+}
+
+ssize_t __intel_spi_write(struct spi_nor *nor, loff_t to, size_t len,
+			  const u_char *write_buf)
+{
+	struct intel_spi *ispi = nor->priv;
+	size_t block_size, retlen = 0;
+	u32 val, status;
+	ssize_t ret;
+
+	/* Not needed with HW sequencer write, make sure it is cleared */
+	ispi->atomic_preopcode = 0;
+
+	while (len > 0) {
+		block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ);
+
+		/* Write cannot cross 4K boundary */
+		block_size = min_t(loff_t, to + block_size,
+				   round_up(to + 1, SZ_4K)) - to;
+
+		writel(to, ispi->base + FADDR);
+
+		val = readl(ispi->base + HSFSTS_CTL);
+		val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK);
+		val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE;
+		val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT;
+		val |= HSFSTS_CTL_FCYCLE_WRITE;
+
+		ret = intel_spi_write_block(ispi, write_buf, block_size);
+		if (ret) {
+			dev_err(ispi->dev, "failed to write block\n");
+			return ret;
+		}
+
+		/* Start the write now */
+		val |= HSFSTS_CTL_FGO;
+		writel(val, ispi->base + HSFSTS_CTL);
+
+		ret = intel_spi_wait_hw_busy(ispi);
+		if (ret) {
+			dev_err(ispi->dev, "timeout\n");
+			return ret;
+		}
+
+		status = readl(ispi->base + HSFSTS_CTL);
+		if (status & HSFSTS_CTL_FCERR)
+			ret = -EIO;
+		else if (status & HSFSTS_CTL_AEL)
+			ret = -EACCES;
+
+		if (ret < 0) {
+			dev_err(ispi->dev, "write error: %llx: %#x\n", to,
+				status);
+			return ret;
+		}
+
+		len -= block_size;
+		to += block_size;
+		retlen += block_size;
+		write_buf += block_size;
+	}
+
+	return retlen;
+}
+
+int __intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf, size_t len)
+{
+	struct intel_spi *ispi = nor->priv;
+	int ret;
+
+	/*
+	 * This is handled with atomic operation and preop code in Intel
+	 * controller so we only verify that it is available. If the
+	 * controller is not locked, program the opcode to the PREOP
+	 * register for later use.
+	 *
+	 * When hardware sequencer is used there is no need to program
+	 * any opcodes (it handles them automatically as part of a command).
+	 */
+	if (opcode == SPINOR_OP_WREN) {
+		u16 preop;
+
+		if (!ispi->swseq_reg)
+			return 0;
+
+		preop = readw(ispi->sregs + PREOP_OPTYPE);
+		if ((preop & 0xff) != opcode && (preop >> 8) != opcode) {
+			if (ispi->locked)
+				return -EINVAL;
+			writel(opcode, ispi->sregs + PREOP_OPTYPE);
+		}
+
+		/*
+		 * This enables atomic sequence on next SW sycle. Will
+		 * be cleared after next operation.
+		 */
+		ispi->atomic_preopcode = opcode;
+		return 0;
+	}
+
+	/*
+	 * We hope that HW sequencer will do the right thing automatically and
+	 * with the SW sequencer we cannot use preopcode anyway, so just ignore
+	 * the Write Disable operation and pretend it was completed
+	 * successfully.
+	 */
+	if (opcode == SPINOR_OP_WRDI)
+		return 0;
+
+	writel(0, ispi->base + FADDR);
+
+	/* Write the value beforehand */
+	ret = intel_spi_write_block(ispi, buf, len);
+	if (ret)
+		return ret;
+
+	if (ispi->swseq_reg)
+		return intel_spi_sw_cycle(ispi, opcode, len,
+					  OPTYPE_WRITE_NO_ADDR);
+	return intel_spi_hw_cycle(ispi, opcode, len);
+}
+
+int __configure_lvscc_uvscc(struct intel_spi *ispi)
+{
+	u32 lvscc, uvscc;
+	/*
+	 * Determine whether erase operation should use HW or SW sequencer.
+	 *
+	 * The HW sequencer has a predefined list of opcodes, with only the
+	 * erase opcode being programmable in LVSCC and UVSCC registers.
+	 * If these registers don't contain a valid erase opcode, erase
+	 * cannot be done using HW sequencer.
+	 */
+	lvscc = readl(ispi->base + LVSCC);
+	uvscc = readl(ispi->base + UVSCC);
+	if (!(lvscc & ERASE_OPCODE_MASK) || !(uvscc & ERASE_OPCODE_MASK))
+		ispi->swseq_erase = true;
+	/* SPI controller on Intel BXT supports 64K erase opcode */
+	if (ispi->info->type == INTEL_SPI_BXT && !ispi->swseq_erase)
+		if (!(lvscc & ERASE_64K_OPCODE_MASK) ||
+		    !(uvscc & ERASE_64K_OPCODE_MASK))
+			ispi->erase_64k = false;
+
+	if (ispi->sregs == NULL && (ispi->swseq_reg || ispi->swseq_erase)) {
+		dev_err(ispi->dev, "software sequencer not supported, but required\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int __intel_sw_cycle_write(struct intel_spi *ispi, int optype, u8 atomic_preopcode)
+{
+	u32 val = 0;
+	u16 preop;
+
+	switch (optype) {
+	case OPTYPE_WRITE_NO_ADDR:
+	case OPTYPE_WRITE_WITH_ADDR:
+		/* Pick matching preopcode for the atomic sequence */
+		preop = readw(ispi->sregs + PREOP_OPTYPE);
+		if ((preop & 0xff) == atomic_preopcode)
+			; /* Do nothing */
+		else if ((preop >> 8) == atomic_preopcode)
+			val |= SSFSTS_CTL_SPOP;
+		else
+			return -EINVAL;
+
+		/* Enable atomic sequence */
+		val |= SSFSTS_CTL_ACS;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return val;
+}
+
+void __intel_byt_rw_config(struct intel_spi *ispi)
+{
+	u32 val;
+
+	/* Disable write protection */
+	val = readl(ispi->base + BYT_BCR);
+	if (!(val & BYT_BCR_WPD)) {
+		val |= BYT_BCR_WPD;
+		writel(val, ispi->base + BYT_BCR);
+		val = readl(ispi->base + BYT_BCR);
+	}
+
+	ispi->writeable = !!(val & BYT_BCR_WPD);
+}
+
+void __intel_bxt_rw_config(struct intel_spi *ispi)
+{
+	ispi->erase_64k = true;
+}
+MODULE_LICENSE("GPL v2");
-- 
2.31.1


-- 


This e-mail and any attachments may contain information that is 
privileged, confidential,  and/or exempt from disclosure under applicable 
law.  If you are not the intended recipient, you are hereby notified that 
any disclosure, copying, distribution or use of any information contained 
herein is strictly prohibited. If you have received this transmission in 
error, please immediately notify the sender and destroy the original 
transmission and any attachments, whether in electronic or hard copy 
format, without reading or saving.













______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/4] mtd: intel-spi: add read only stubs
  2021-09-10 21:13 [PATCH 0/4] mtd: intel-spi: split read/write modes Mauro Lima
                   ` (2 preceding siblings ...)
  2021-09-10 21:13 ` [PATCH 3/4] mtd: intel-spi: moving write/erase functions Mauro Lima
@ 2021-09-10 21:13 ` Mauro Lima
  2021-09-13 10:06   ` Mika Westerberg
  2021-09-13  9:59 ` [PATCH 0/4] mtd: intel-spi: split read/write modes Mika Westerberg
  4 siblings, 1 reply; 8+ messages in thread
From: Mauro Lima @ 2021-09-10 21:13 UTC (permalink / raw)
  To: linux-mtd
  Cc: daniel.gutson, richard, tudor.ambarus, miquel.raynal, richard,
	vigneshr, mika.westerberg, mauro.lima

Add read only stub functions (as __weak) in read only mode,
so they can be override on read-write mode.
Remove the (DANGEROUS) tag in read only mode.
Add write mode option if pci or platform driver is selected.
Change the intel-spi recepie to be able to build read only
or read-write mode.

Suggested-by: Daniel Gutson <daniel.gutson@eclypsium.com>
Suggested-by: Richard Hughes <richard@hughsie.com>
Signed-off-by: Mauro Lima <mauro.lima@eclypsium.com>
---
 drivers/mtd/spi-nor/controllers/Kconfig       | 50 +++++++++++++------
 drivers/mtd/spi-nor/controllers/Makefile      |  4 +-
 .../mtd/spi-nor/controllers/intel-spi-ro.c    | 50 +++++++++++++++++++
 .../mtd/spi-nor/controllers/intel-spi-rw.h    |  1 +
 4 files changed, 88 insertions(+), 17 deletions(-)
 create mode 100644 drivers/mtd/spi-nor/controllers/intel-spi-ro.c

diff --git a/drivers/mtd/spi-nor/controllers/Kconfig b/drivers/mtd/spi-nor/controllers/Kconfig
index 5c0e0ec2e6d1..c4f2505c9302 100644
--- a/drivers/mtd/spi-nor/controllers/Kconfig
+++ b/drivers/mtd/spi-nor/controllers/Kconfig
@@ -30,35 +30,53 @@ config SPI_NXP_SPIFI
 config SPI_INTEL_SPI
 	tristate
 
+config SPI_INTEL_SPI_RO
+	bool
+	default y if !SPI_INTEL_SPI_W
+	select SPI_INTEL_SPI
+
 config SPI_INTEL_SPI_PCI
-	tristate "Intel PCH/PCU SPI flash PCI driver (DANGEROUS)"
+	tristate
+
+config SPI_INTEL_SPI_PLATFORM
+	tristate
+
+config SPI_INTEL_SPI_PCI_RO
+	tristate "Intel PCH/PCU SPI flash PCI driver"
 	depends on X86 && PCI
-	select SPI_INTEL_SPI
+	select SPI_INTEL_SPI_RO
+	select SPI_INTEL_SPI_PCI
 	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.
+	  read only mode. This controller is present in modern Intel
+	  hardware and is used to hold BIOS and other persistent settings.
 
 	  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)"
+config SPI_INTEL_SPI_PLATFORM_RO
+	tristate "Intel PCH/PCU SPI flash platform driver"
 	depends on X86
+	select SPI_INTEL_SPI_RO
+	select SPI_INTEL_SPI_PLATFORM
+	help
+	  This enables PCI support for the Intel PCH/PCU SPI controller in
+	  read only mode. This controller is present in modern Intel
+	  hardware and is used to hold BIOS and other persistent settings.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called intel-spi-pci.
+
+config SPI_INTEL_SPI_W
+	bool "Enable Intel PCH/PCU SPI controller in write mode (DANGEROUS)"
 	select SPI_INTEL_SPI
+	default n if SPI_INTEL_SPI_PCI || SPI_INTEL_SPI_PLATFORM
+	depends on SPI_INTEL_SPI_PCI || SPI_INTEL_SPI_PLATFORM
 	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
+	  This enables {PCI|PLATFORM} support for the Intel PCH/PCU controller
+	  in master mode. Enabling this mode 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.
diff --git a/drivers/mtd/spi-nor/controllers/Makefile b/drivers/mtd/spi-nor/controllers/Makefile
index 1933a7c2c30b..a4faeace67fc 100644
--- a/drivers/mtd/spi-nor/controllers/Makefile
+++ b/drivers/mtd/spi-nor/controllers/Makefile
@@ -3,6 +3,8 @@ 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
-intel-spi-y := intel-spi-base.o intel-spi-w.o
+intel-spi-y := intel-spi-base.o
+intel-spi-$(CONFIG_SPI_INTEL_SPI_RO) += intel-spi-ro.o
+intel-spi-$(CONFIG_SPI_INTEL_SPI_W) += intel-spi-w.o
 obj-$(CONFIG_SPI_INTEL_SPI_PCI)	+= intel-spi-pci.o
 obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM)	+= intel-spi-platform.o
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-ro.c b/drivers/mtd/spi-nor/controllers/intel-spi-ro.c
new file mode 100644
index 000000000000..4c52c2bb65ef
--- /dev/null
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-ro.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "intel-spi-rw.h"
+
+bool __weak is_write_enabled(void)
+{
+	return false;
+}
+
+int __weak __intel_spi_erase(struct spi_nor *nor, loff_t offs)
+{
+	return -EINVAL;
+}
+
+ssize_t __weak __intel_spi_write(struct spi_nor *nor, loff_t to, size_t len,
+				 const u_char *write_buf)
+{
+	return -EINVAL;
+}
+
+int __weak __intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf,
+				 size_t len)
+{
+	return -EINVAL;
+}
+
+/* We don't need erase op */
+int __weak __configure_lvscc_uvscc(struct intel_spi *ispi)
+{
+	ispi->erase_64k = false;
+	return 0;
+}
+
+void __weak __intel_bxt_rw_config(struct intel_spi *ispi)
+{
+	(void)ispi;
+}
+
+void __weak __intel_byt_rw_config(struct intel_spi *ispi)
+{
+	(void)ispi;
+}
+
+int __weak __intel_sw_cycle_write(struct intel_spi *ispi, int optype, u8 atomic_preopcode)
+{
+	/* not supported op */
+	return -EINVAL;
+}
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-rw.h b/drivers/mtd/spi-nor/controllers/intel-spi-rw.h
index 46c6461a8a7b..b682db03f17a 100644
--- a/drivers/mtd/spi-nor/controllers/intel-spi-rw.h
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-rw.h
@@ -10,6 +10,7 @@ int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len, int optype
 int intel_spi_wait_hw_busy(struct intel_spi *ispi);
 int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len);
 
+void check_mode(void);
 bool is_write_enabled(void);
 int  __intel_spi_erase(struct spi_nor *nor, loff_t offs);
 ssize_t  __intel_spi_write(struct spi_nor *nor, loff_t to, size_t len, const u_char *write_buf);
-- 
2.31.1


-- 


This e-mail and any attachments may contain information that is 
privileged, confidential,  and/or exempt from disclosure under applicable 
law.  If you are not the intended recipient, you are hereby notified that 
any disclosure, copying, distribution or use of any information contained 
herein is strictly prohibited. If you have received this transmission in 
error, please immediately notify the sender and destroy the original 
transmission and any attachments, whether in electronic or hard copy 
format, without reading or saving.













______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/4] mtd: intel-spi: split read/write modes
  2021-09-10 21:13 [PATCH 0/4] mtd: intel-spi: split read/write modes Mauro Lima
                   ` (3 preceding siblings ...)
  2021-09-10 21:13 ` [PATCH 4/4] mtd: intel-spi: add read only stubs Mauro Lima
@ 2021-09-13  9:59 ` Mika Westerberg
  4 siblings, 0 replies; 8+ messages in thread
From: Mika Westerberg @ 2021-09-13  9:59 UTC (permalink / raw)
  To: Mauro Lima
  Cc: linux-mtd, daniel.gutson, richard, tudor.ambarus, miquel.raynal,
	richard, vigneshr

Hi,

On Fri, Sep 10, 2021 at 06:13:44PM -0300, Mauro Lima wrote:
> The purpose of the following patchset is to split read/write
> functionality from the Intel PCH/PCU SPI flash driver.
> Being able to use the driver in read-only mode (harmless), the users
> can get important firmware information from userspace which also
> includes being able to perform firmware attestation to verify
> integrity.

The SPI-NOR maintainers wanted that the driver converted first to use
"SPI MEM" framework before any new features can be added. I'm currently
working on that.

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/4] mtd: intel-spi: rename intel-spi to intel-spi-base
  2021-09-10 21:13 ` [PATCH 1/4] mtd: intel-spi: rename intel-spi to intel-spi-base Mauro Lima
@ 2021-09-13 10:00   ` Mika Westerberg
  0 siblings, 0 replies; 8+ messages in thread
From: Mika Westerberg @ 2021-09-13 10:00 UTC (permalink / raw)
  To: Mauro Lima
  Cc: linux-mtd, daniel.gutson, richard, tudor.ambarus, miquel.raynal,
	richard, vigneshr

On Fri, Sep 10, 2021 at 06:13:45PM -0300, Mauro Lima wrote:
> Rename the files we want to split as base files.
> Include the new files in intel-spi-{pci|platform}.c.
> Change the intel-spi obj Makefile to be built with
> intel-spi-base.

I don't think this brings any benefits over the existing name.
Furthermore if this needs to be done, -core.c would make more sense.
IMHO.

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 4/4] mtd: intel-spi: add read only stubs
  2021-09-10 21:13 ` [PATCH 4/4] mtd: intel-spi: add read only stubs Mauro Lima
@ 2021-09-13 10:06   ` Mika Westerberg
  0 siblings, 0 replies; 8+ messages in thread
From: Mika Westerberg @ 2021-09-13 10:06 UTC (permalink / raw)
  To: Mauro Lima
  Cc: linux-mtd, daniel.gutson, richard, tudor.ambarus, miquel.raynal,
	richard, vigneshr

On Fri, Sep 10, 2021 at 06:13:48PM -0300, Mauro Lima wrote:
> Add read only stub functions (as __weak) in read only mode,
> so they can be override on read-write mode.
> Remove the (DANGEROUS) tag in read only mode.
> Add write mode option if pci or platform driver is selected.
> Change the intel-spi recepie to be able to build read only
> or read-write mode.

This looks pretty convoluted way to get rid of the "DANGEROUS" in the
name ;-)

What is the firmware information fwupd is looking for? Perhaps there are
other, better, ways to do this?

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-09-13 10:07 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-10 21:13 [PATCH 0/4] mtd: intel-spi: split read/write modes Mauro Lima
2021-09-10 21:13 ` [PATCH 1/4] mtd: intel-spi: rename intel-spi to intel-spi-base Mauro Lima
2021-09-13 10:00   ` Mika Westerberg
2021-09-10 21:13 ` [PATCH 2/4] mtd: intel-spi: move chip internals into a defs.h Mauro Lima
2021-09-10 21:13 ` [PATCH 3/4] mtd: intel-spi: moving write/erase functions Mauro Lima
2021-09-10 21:13 ` [PATCH 4/4] mtd: intel-spi: add read only stubs Mauro Lima
2021-09-13 10:06   ` Mika Westerberg
2021-09-13  9:59 ` [PATCH 0/4] mtd: intel-spi: split read/write modes Mika Westerberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.