diff options
author | Brian Norris <computersforpeace@gmail.com> | 2017-05-01 20:08:10 -0400 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2017-05-01 20:08:10 -0400 |
commit | 47228ca57e845d3d9196eb4e232b7cf6217a9beb (patch) | |
tree | 04cbba672067e40eb11537a26e081c6175aaad20 /drivers/mtd | |
parent | 57e363b8c45b6626b012f6ce39a2f70adf6b49fc (diff) | |
parent | 8abe904dc82772bf1635fcc5765433c672f0a875 (diff) |
Merge tag 'spi-nor/for-4.12-v2' of git://github.com/spi-nor/linux into MTD
From Cyrille:
"""
This pull request contains the following notable changes:
- fixes in the hisi SPI controller driver.
- fixes in the intel SPI controller driver.
- fixes in the Mediatek SPI controller driver.
- fixes to some SPI flash memories not supported the Chip Erase command.
- add support to some new memory parts (Winbond, Macronix, Micron, ESMT).
- add new driver for the STM32 QSPI controller.
"""
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/spi-nor/Kconfig | 7 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/hisi-sfc.c | 5 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/intel-spi.c | 4 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/mtk-quadspi.c | 27 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/spi-nor.c | 18 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/stm32-quadspi.c | 693 |
7 files changed, 749 insertions, 6 deletions
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index 7252087ef407..bfdfb1e72b38 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig | |||
@@ -106,4 +106,11 @@ config SPI_INTEL_SPI_PLATFORM | |||
106 | To compile this driver as a module, choose M here: the module | 106 | To compile this driver as a module, choose M here: the module |
107 | will be called intel-spi-platform. | 107 | will be called intel-spi-platform. |
108 | 108 | ||
109 | config SPI_STM32_QUADSPI | ||
110 | tristate "STM32 Quad SPI controller" | ||
111 | depends on ARCH_STM32 | ||
112 | help | ||
113 | This enables support for the STM32 Quad SPI controller. | ||
114 | We only connect the NOR to this controller. | ||
115 | |||
109 | endif # MTD_SPI_NOR | 116 | endif # MTD_SPI_NOR |
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile index 72238a793198..285aab86c7ca 100644 --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile | |||
@@ -8,3 +8,4 @@ obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o | |||
8 | obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o | 8 | obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o |
9 | obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o | 9 | obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o |
10 | obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o | 10 | obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o |
11 | obj-$(CONFIG_SPI_STM32_QUADSPI) += stm32-quadspi.o \ No newline at end of file | ||
diff --git a/drivers/mtd/spi-nor/hisi-sfc.c b/drivers/mtd/spi-nor/hisi-sfc.c index 20378b0d55e9..a286350627a6 100644 --- a/drivers/mtd/spi-nor/hisi-sfc.c +++ b/drivers/mtd/spi-nor/hisi-sfc.c | |||
@@ -448,8 +448,11 @@ static int hisi_spi_nor_probe(struct platform_device *pdev) | |||
448 | if (!host->buffer) | 448 | if (!host->buffer) |
449 | return -ENOMEM; | 449 | return -ENOMEM; |
450 | 450 | ||
451 | ret = clk_prepare_enable(host->clk); | ||
452 | if (ret) | ||
453 | return ret; | ||
454 | |||
451 | mutex_init(&host->lock); | 455 | mutex_init(&host->lock); |
452 | clk_prepare_enable(host->clk); | ||
453 | hisi_spi_nor_init(host); | 456 | hisi_spi_nor_init(host); |
454 | ret = hisi_spi_nor_register_all(host); | 457 | ret = hisi_spi_nor_register_all(host); |
455 | if (ret) | 458 | if (ret) |
diff --git a/drivers/mtd/spi-nor/intel-spi.c b/drivers/mtd/spi-nor/intel-spi.c index a10f6027b386..986a3d020a3a 100644 --- a/drivers/mtd/spi-nor/intel-spi.c +++ b/drivers/mtd/spi-nor/intel-spi.c | |||
@@ -704,7 +704,7 @@ static void intel_spi_fill_partition(struct intel_spi *ispi, | |||
704 | * whole partition read-only to be on the safe side. | 704 | * whole partition read-only to be on the safe side. |
705 | */ | 705 | */ |
706 | if (intel_spi_is_protected(ispi, base, limit)) | 706 | if (intel_spi_is_protected(ispi, base, limit)) |
707 | ispi->writeable = 0; | 707 | ispi->writeable = false; |
708 | 708 | ||
709 | end = (limit << 12) + 4096; | 709 | end = (limit << 12) + 4096; |
710 | if (end > part->size) | 710 | if (end > part->size) |
@@ -728,7 +728,7 @@ struct intel_spi *intel_spi_probe(struct device *dev, | |||
728 | 728 | ||
729 | ispi->base = devm_ioremap_resource(dev, mem); | 729 | ispi->base = devm_ioremap_resource(dev, mem); |
730 | if (IS_ERR(ispi->base)) | 730 | if (IS_ERR(ispi->base)) |
731 | return ispi->base; | 731 | return ERR_CAST(ispi->base); |
732 | 732 | ||
733 | ispi->dev = dev; | 733 | ispi->dev = dev; |
734 | ispi->info = info; | 734 | ispi->info = info; |
diff --git a/drivers/mtd/spi-nor/mtk-quadspi.c b/drivers/mtd/spi-nor/mtk-quadspi.c index e661877c23de..b6377707ce32 100644 --- a/drivers/mtd/spi-nor/mtk-quadspi.c +++ b/drivers/mtd/spi-nor/mtk-quadspi.c | |||
@@ -104,6 +104,8 @@ | |||
104 | #define MTK_NOR_MAX_RX_TX_SHIFT 6 | 104 | #define MTK_NOR_MAX_RX_TX_SHIFT 6 |
105 | /* can shift up to 56 bits (7 bytes) transfer by MTK_NOR_PRG_CMD */ | 105 | /* can shift up to 56 bits (7 bytes) transfer by MTK_NOR_PRG_CMD */ |
106 | #define MTK_NOR_MAX_SHIFT 7 | 106 | #define MTK_NOR_MAX_SHIFT 7 |
107 | /* nor controller 4-byte address mode enable bit */ | ||
108 | #define MTK_NOR_4B_ADDR_EN BIT(4) | ||
107 | 109 | ||
108 | /* Helpers for accessing the program data / shift data registers */ | 110 | /* Helpers for accessing the program data / shift data registers */ |
109 | #define MTK_NOR_PRG_REG(n) (MTK_NOR_PRGDATA0_REG + 4 * (n)) | 111 | #define MTK_NOR_PRG_REG(n) (MTK_NOR_PRGDATA0_REG + 4 * (n)) |
@@ -230,10 +232,35 @@ static int mt8173_nor_write_buffer_disable(struct mt8173_nor *mt8173_nor) | |||
230 | 10000); | 232 | 10000); |
231 | } | 233 | } |
232 | 234 | ||
235 | static void mt8173_nor_set_addr_width(struct mt8173_nor *mt8173_nor) | ||
236 | { | ||
237 | u8 val; | ||
238 | struct spi_nor *nor = &mt8173_nor->nor; | ||
239 | |||
240 | val = readb(mt8173_nor->base + MTK_NOR_DUAL_REG); | ||
241 | |||
242 | switch (nor->addr_width) { | ||
243 | case 3: | ||
244 | val &= ~MTK_NOR_4B_ADDR_EN; | ||
245 | break; | ||
246 | case 4: | ||
247 | val |= MTK_NOR_4B_ADDR_EN; | ||
248 | break; | ||
249 | default: | ||
250 | dev_warn(mt8173_nor->dev, "Unexpected address width %u.\n", | ||
251 | nor->addr_width); | ||
252 | break; | ||
253 | } | ||
254 | |||
255 | writeb(val, mt8173_nor->base + MTK_NOR_DUAL_REG); | ||
256 | } | ||
257 | |||
233 | static void mt8173_nor_set_addr(struct mt8173_nor *mt8173_nor, u32 addr) | 258 | static void mt8173_nor_set_addr(struct mt8173_nor *mt8173_nor, u32 addr) |
234 | { | 259 | { |
235 | int i; | 260 | int i; |
236 | 261 | ||
262 | mt8173_nor_set_addr_width(mt8173_nor); | ||
263 | |||
237 | for (i = 0; i < 3; i++) { | 264 | for (i = 0; i < 3; i++) { |
238 | writeb(addr & 0xff, mt8173_nor->base + MTK_NOR_RADR0_REG + i * 4); | 265 | writeb(addr & 0xff, mt8173_nor->base + MTK_NOR_RADR0_REG + i * 4); |
239 | addr >>= 8; | 266 | addr >>= 8; |
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 1ae872bfc3ba..36684ca7aa24 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c | |||
@@ -85,6 +85,7 @@ struct flash_info { | |||
85 | * Use dedicated 4byte address op codes | 85 | * Use dedicated 4byte address op codes |
86 | * to support memory size above 128Mib. | 86 | * to support memory size above 128Mib. |
87 | */ | 87 | */ |
88 | #define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */ | ||
88 | }; | 89 | }; |
89 | 90 | ||
90 | #define JEDEC_MFR(info) ((info)->id[0]) | 91 | #define JEDEC_MFR(info) ((info)->id[0]) |
@@ -960,6 +961,8 @@ static const struct flash_info spi_nor_ids[] = { | |||
960 | 961 | ||
961 | /* ESMT */ | 962 | /* ESMT */ |
962 | { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) }, | 963 | { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) }, |
964 | { "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) }, | ||
965 | { "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_LOCK) }, | ||
963 | 966 | ||
964 | /* Everspin */ | 967 | /* Everspin */ |
965 | { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, | 968 | { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, |
@@ -1013,11 +1016,14 @@ static const struct flash_info spi_nor_ids[] = { | |||
1013 | { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) }, | 1016 | { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) }, |
1014 | { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, | 1017 | { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, |
1015 | { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) }, | 1018 | { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) }, |
1019 | { "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4, SECT_4K) }, | ||
1020 | { "mx25u4035", INFO(0xc22533, 0, 64 * 1024, 8, SECT_4K) }, | ||
1021 | { "mx25u8035", INFO(0xc22534, 0, 64 * 1024, 16, SECT_4K) }, | ||
1016 | { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, | 1022 | { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, |
1017 | { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, | 1023 | { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, |
1018 | { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, | 1024 | { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, |
1019 | { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, | 1025 | { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, |
1020 | { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K) }, | 1026 | { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, |
1021 | { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, | 1027 | { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, |
1022 | { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) }, | 1028 | { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) }, |
1023 | { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, | 1029 | { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, |
@@ -1031,10 +1037,11 @@ static const struct flash_info spi_nor_ids[] = { | |||
1031 | { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, | 1037 | { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, |
1032 | { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, | 1038 | { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, |
1033 | { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, | 1039 | { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, |
1040 | { "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, | ||
1034 | { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, | 1041 | { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, |
1035 | { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, | 1042 | { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, |
1036 | { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, | 1043 | { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, |
1037 | { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, | 1044 | { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, |
1038 | 1045 | ||
1039 | /* PMC */ | 1046 | /* PMC */ |
1040 | { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, | 1047 | { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, |
@@ -1128,6 +1135,9 @@ static const struct flash_info spi_nor_ids[] = { | |||
1128 | { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, | 1135 | { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, |
1129 | { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, | 1136 | { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, |
1130 | { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, | 1137 | { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, |
1138 | { "w25q20cl", INFO(0xef4012, 0, 64 * 1024, 4, SECT_4K) }, | ||
1139 | { "w25q20bw", INFO(0xef5012, 0, 64 * 1024, 4, SECT_4K) }, | ||
1140 | { "w25q20ew", INFO(0xef6012, 0, 64 * 1024, 4, SECT_4K) }, | ||
1131 | { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, | 1141 | { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, |
1132 | { | 1142 | { |
1133 | "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, | 1143 | "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, |
@@ -1629,6 +1639,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) | |||
1629 | nor->flags |= SNOR_F_USE_FSR; | 1639 | nor->flags |= SNOR_F_USE_FSR; |
1630 | if (info->flags & SPI_NOR_HAS_TB) | 1640 | if (info->flags & SPI_NOR_HAS_TB) |
1631 | nor->flags |= SNOR_F_HAS_SR_TB; | 1641 | nor->flags |= SNOR_F_HAS_SR_TB; |
1642 | if (info->flags & NO_CHIP_ERASE) | ||
1643 | nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; | ||
1632 | 1644 | ||
1633 | #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS | 1645 | #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS |
1634 | /* prefer "small sector" erase if possible */ | 1646 | /* prefer "small sector" erase if possible */ |
diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c new file mode 100644 index 000000000000..ae45f81b8cd3 --- /dev/null +++ b/drivers/mtd/spi-nor/stm32-quadspi.c | |||
@@ -0,0 +1,693 @@ | |||
1 | /* | ||
2 | * stm32_quadspi.c | ||
3 | * | ||
4 | * Copyright (C) 2017, Ludovic Barre | ||
5 | * | ||
6 | * License terms: GNU General Public License (GPL), version 2 | ||
7 | */ | ||
8 | #include <linux/clk.h> | ||
9 | #include <linux/errno.h> | ||
10 | #include <linux/io.h> | ||
11 | #include <linux/iopoll.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/mtd/mtd.h> | ||
15 | #include <linux/mtd/partitions.h> | ||
16 | #include <linux/mtd/spi-nor.h> | ||
17 | #include <linux/mutex.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_device.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/reset.h> | ||
22 | |||
23 | #define QUADSPI_CR 0x00 | ||
24 | #define CR_EN BIT(0) | ||
25 | #define CR_ABORT BIT(1) | ||
26 | #define CR_DMAEN BIT(2) | ||
27 | #define CR_TCEN BIT(3) | ||
28 | #define CR_SSHIFT BIT(4) | ||
29 | #define CR_DFM BIT(6) | ||
30 | #define CR_FSEL BIT(7) | ||
31 | #define CR_FTHRES_SHIFT 8 | ||
32 | #define CR_FTHRES_MASK GENMASK(12, 8) | ||
33 | #define CR_FTHRES(n) (((n) << CR_FTHRES_SHIFT) & CR_FTHRES_MASK) | ||
34 | #define CR_TEIE BIT(16) | ||
35 | #define CR_TCIE BIT(17) | ||
36 | #define CR_FTIE BIT(18) | ||
37 | #define CR_SMIE BIT(19) | ||
38 | #define CR_TOIE BIT(20) | ||
39 | #define CR_PRESC_SHIFT 24 | ||
40 | #define CR_PRESC_MASK GENMASK(31, 24) | ||
41 | #define CR_PRESC(n) (((n) << CR_PRESC_SHIFT) & CR_PRESC_MASK) | ||
42 | |||
43 | #define QUADSPI_DCR 0x04 | ||
44 | #define DCR_CSHT_SHIFT 8 | ||
45 | #define DCR_CSHT_MASK GENMASK(10, 8) | ||
46 | #define DCR_CSHT(n) (((n) << DCR_CSHT_SHIFT) & DCR_CSHT_MASK) | ||
47 | #define DCR_FSIZE_SHIFT 16 | ||
48 | #define DCR_FSIZE_MASK GENMASK(20, 16) | ||
49 | #define DCR_FSIZE(n) (((n) << DCR_FSIZE_SHIFT) & DCR_FSIZE_MASK) | ||
50 | |||
51 | #define QUADSPI_SR 0x08 | ||
52 | #define SR_TEF BIT(0) | ||
53 | #define SR_TCF BIT(1) | ||
54 | #define SR_FTF BIT(2) | ||
55 | #define SR_SMF BIT(3) | ||
56 | #define SR_TOF BIT(4) | ||
57 | #define SR_BUSY BIT(5) | ||
58 | #define SR_FLEVEL_SHIFT 8 | ||
59 | #define SR_FLEVEL_MASK GENMASK(13, 8) | ||
60 | |||
61 | #define QUADSPI_FCR 0x0c | ||
62 | #define FCR_CTCF BIT(1) | ||
63 | |||
64 | #define QUADSPI_DLR 0x10 | ||
65 | |||
66 | #define QUADSPI_CCR 0x14 | ||
67 | #define CCR_INST_SHIFT 0 | ||
68 | #define CCR_INST_MASK GENMASK(7, 0) | ||
69 | #define CCR_INST(n) (((n) << CCR_INST_SHIFT) & CCR_INST_MASK) | ||
70 | #define CCR_IMODE_NONE (0U << 8) | ||
71 | #define CCR_IMODE_1 (1U << 8) | ||
72 | #define CCR_IMODE_2 (2U << 8) | ||
73 | #define CCR_IMODE_4 (3U << 8) | ||
74 | #define CCR_ADMODE_NONE (0U << 10) | ||
75 | #define CCR_ADMODE_1 (1U << 10) | ||
76 | #define CCR_ADMODE_2 (2U << 10) | ||
77 | #define CCR_ADMODE_4 (3U << 10) | ||
78 | #define CCR_ADSIZE_SHIFT 12 | ||
79 | #define CCR_ADSIZE_MASK GENMASK(13, 12) | ||
80 | #define CCR_ADSIZE(n) (((n) << CCR_ADSIZE_SHIFT) & CCR_ADSIZE_MASK) | ||
81 | #define CCR_ABMODE_NONE (0U << 14) | ||
82 | #define CCR_ABMODE_1 (1U << 14) | ||
83 | #define CCR_ABMODE_2 (2U << 14) | ||
84 | #define CCR_ABMODE_4 (3U << 14) | ||
85 | #define CCR_ABSIZE_8 (0U << 16) | ||
86 | #define CCR_ABSIZE_16 (1U << 16) | ||
87 | #define CCR_ABSIZE_24 (2U << 16) | ||
88 | #define CCR_ABSIZE_32 (3U << 16) | ||
89 | #define CCR_DCYC_SHIFT 18 | ||
90 | #define CCR_DCYC_MASK GENMASK(22, 18) | ||
91 | #define CCR_DCYC(n) (((n) << CCR_DCYC_SHIFT) & CCR_DCYC_MASK) | ||
92 | #define CCR_DMODE_NONE (0U << 24) | ||
93 | #define CCR_DMODE_1 (1U << 24) | ||
94 | #define CCR_DMODE_2 (2U << 24) | ||
95 | #define CCR_DMODE_4 (3U << 24) | ||
96 | #define CCR_FMODE_INDW (0U << 26) | ||
97 | #define CCR_FMODE_INDR (1U << 26) | ||
98 | #define CCR_FMODE_APM (2U << 26) | ||
99 | #define CCR_FMODE_MM (3U << 26) | ||
100 | |||
101 | #define QUADSPI_AR 0x18 | ||
102 | #define QUADSPI_ABR 0x1c | ||
103 | #define QUADSPI_DR 0x20 | ||
104 | #define QUADSPI_PSMKR 0x24 | ||
105 | #define QUADSPI_PSMAR 0x28 | ||
106 | #define QUADSPI_PIR 0x2c | ||
107 | #define QUADSPI_LPTR 0x30 | ||
108 | #define LPTR_DFT_TIMEOUT 0x10 | ||
109 | |||
110 | #define FSIZE_VAL(size) (__fls(size) - 1) | ||
111 | |||
112 | #define STM32_MAX_MMAP_SZ SZ_256M | ||
113 | #define STM32_MAX_NORCHIP 2 | ||
114 | |||
115 | #define STM32_QSPI_FIFO_TIMEOUT_US 30000 | ||
116 | #define STM32_QSPI_BUSY_TIMEOUT_US 100000 | ||
117 | |||
118 | struct stm32_qspi_flash { | ||
119 | struct spi_nor nor; | ||
120 | struct stm32_qspi *qspi; | ||
121 | u32 cs; | ||
122 | u32 fsize; | ||
123 | u32 presc; | ||
124 | u32 read_mode; | ||
125 | bool registered; | ||
126 | }; | ||
127 | |||
128 | struct stm32_qspi { | ||
129 | struct device *dev; | ||
130 | void __iomem *io_base; | ||
131 | void __iomem *mm_base; | ||
132 | resource_size_t mm_size; | ||
133 | u32 nor_num; | ||
134 | struct clk *clk; | ||
135 | u32 clk_rate; | ||
136 | struct stm32_qspi_flash flash[STM32_MAX_NORCHIP]; | ||
137 | struct completion cmd_completion; | ||
138 | |||
139 | /* | ||
140 | * to protect device configuration, could be different between | ||
141 | * 2 flash access (bk1, bk2) | ||
142 | */ | ||
143 | struct mutex lock; | ||
144 | }; | ||
145 | |||
146 | struct stm32_qspi_cmd { | ||
147 | u8 addr_width; | ||
148 | u8 dummy; | ||
149 | bool tx_data; | ||
150 | u8 opcode; | ||
151 | u32 framemode; | ||
152 | u32 qspimode; | ||
153 | u32 addr; | ||
154 | size_t len; | ||
155 | void *buf; | ||
156 | }; | ||
157 | |||
158 | static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi) | ||
159 | { | ||
160 | u32 cr; | ||
161 | int err = 0; | ||
162 | |||
163 | if (readl_relaxed(qspi->io_base + QUADSPI_SR) & SR_TCF) | ||
164 | return 0; | ||
165 | |||
166 | reinit_completion(&qspi->cmd_completion); | ||
167 | cr = readl_relaxed(qspi->io_base + QUADSPI_CR); | ||
168 | writel_relaxed(cr | CR_TCIE, qspi->io_base + QUADSPI_CR); | ||
169 | |||
170 | if (!wait_for_completion_interruptible_timeout(&qspi->cmd_completion, | ||
171 | msecs_to_jiffies(1000))) | ||
172 | err = -ETIMEDOUT; | ||
173 | |||
174 | writel_relaxed(cr, qspi->io_base + QUADSPI_CR); | ||
175 | return err; | ||
176 | } | ||
177 | |||
178 | static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi) | ||
179 | { | ||
180 | u32 sr; | ||
181 | |||
182 | return readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR, sr, | ||
183 | !(sr & SR_BUSY), 10, | ||
184 | STM32_QSPI_BUSY_TIMEOUT_US); | ||
185 | } | ||
186 | |||
187 | static void stm32_qspi_set_framemode(struct spi_nor *nor, | ||
188 | struct stm32_qspi_cmd *cmd, bool read) | ||
189 | { | ||
190 | u32 dmode = CCR_DMODE_1; | ||
191 | |||
192 | cmd->framemode = CCR_IMODE_1; | ||
193 | |||
194 | if (read) { | ||
195 | switch (nor->flash_read) { | ||
196 | case SPI_NOR_NORMAL: | ||
197 | case SPI_NOR_FAST: | ||
198 | dmode = CCR_DMODE_1; | ||
199 | break; | ||
200 | case SPI_NOR_DUAL: | ||
201 | dmode = CCR_DMODE_2; | ||
202 | break; | ||
203 | case SPI_NOR_QUAD: | ||
204 | dmode = CCR_DMODE_4; | ||
205 | break; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | cmd->framemode |= cmd->tx_data ? dmode : 0; | ||
210 | cmd->framemode |= cmd->addr_width ? CCR_ADMODE_1 : 0; | ||
211 | } | ||
212 | |||
213 | static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr) | ||
214 | { | ||
215 | *val = readb_relaxed(addr); | ||
216 | } | ||
217 | |||
218 | static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr) | ||
219 | { | ||
220 | writeb_relaxed(*val, addr); | ||
221 | } | ||
222 | |||
223 | static int stm32_qspi_tx_poll(struct stm32_qspi *qspi, | ||
224 | const struct stm32_qspi_cmd *cmd) | ||
225 | { | ||
226 | void (*tx_fifo)(u8 *, void __iomem *); | ||
227 | u32 len = cmd->len, sr; | ||
228 | u8 *buf = cmd->buf; | ||
229 | int ret; | ||
230 | |||
231 | if (cmd->qspimode == CCR_FMODE_INDW) | ||
232 | tx_fifo = stm32_qspi_write_fifo; | ||
233 | else | ||
234 | tx_fifo = stm32_qspi_read_fifo; | ||
235 | |||
236 | while (len--) { | ||
237 | ret = readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR, | ||
238 | sr, (sr & SR_FTF), 10, | ||
239 | STM32_QSPI_FIFO_TIMEOUT_US); | ||
240 | if (ret) { | ||
241 | dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr); | ||
242 | break; | ||
243 | } | ||
244 | tx_fifo(buf++, qspi->io_base + QUADSPI_DR); | ||
245 | } | ||
246 | |||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, | ||
251 | const struct stm32_qspi_cmd *cmd) | ||
252 | { | ||
253 | memcpy_fromio(cmd->buf, qspi->mm_base + cmd->addr, cmd->len); | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int stm32_qspi_tx(struct stm32_qspi *qspi, | ||
258 | const struct stm32_qspi_cmd *cmd) | ||
259 | { | ||
260 | if (!cmd->tx_data) | ||
261 | return 0; | ||
262 | |||
263 | if (cmd->qspimode == CCR_FMODE_MM) | ||
264 | return stm32_qspi_tx_mm(qspi, cmd); | ||
265 | |||
266 | return stm32_qspi_tx_poll(qspi, cmd); | ||
267 | } | ||
268 | |||
269 | static int stm32_qspi_send(struct stm32_qspi_flash *flash, | ||
270 | const struct stm32_qspi_cmd *cmd) | ||
271 | { | ||
272 | struct stm32_qspi *qspi = flash->qspi; | ||
273 | u32 ccr, dcr, cr; | ||
274 | int err; | ||
275 | |||
276 | err = stm32_qspi_wait_nobusy(qspi); | ||
277 | if (err) | ||
278 | goto abort; | ||
279 | |||
280 | dcr = readl_relaxed(qspi->io_base + QUADSPI_DCR) & ~DCR_FSIZE_MASK; | ||
281 | dcr |= DCR_FSIZE(flash->fsize); | ||
282 | writel_relaxed(dcr, qspi->io_base + QUADSPI_DCR); | ||
283 | |||
284 | cr = readl_relaxed(qspi->io_base + QUADSPI_CR); | ||
285 | cr &= ~CR_PRESC_MASK & ~CR_FSEL; | ||
286 | cr |= CR_PRESC(flash->presc); | ||
287 | cr |= flash->cs ? CR_FSEL : 0; | ||
288 | writel_relaxed(cr, qspi->io_base + QUADSPI_CR); | ||
289 | |||
290 | if (cmd->tx_data) | ||
291 | writel_relaxed(cmd->len - 1, qspi->io_base + QUADSPI_DLR); | ||
292 | |||
293 | ccr = cmd->framemode | cmd->qspimode; | ||
294 | |||
295 | if (cmd->dummy) | ||
296 | ccr |= CCR_DCYC(cmd->dummy); | ||
297 | |||
298 | if (cmd->addr_width) | ||
299 | ccr |= CCR_ADSIZE(cmd->addr_width - 1); | ||
300 | |||
301 | ccr |= CCR_INST(cmd->opcode); | ||
302 | writel_relaxed(ccr, qspi->io_base + QUADSPI_CCR); | ||
303 | |||
304 | if (cmd->addr_width && cmd->qspimode != CCR_FMODE_MM) | ||
305 | writel_relaxed(cmd->addr, qspi->io_base + QUADSPI_AR); | ||
306 | |||
307 | err = stm32_qspi_tx(qspi, cmd); | ||
308 | if (err) | ||
309 | goto abort; | ||
310 | |||
311 | if (cmd->qspimode != CCR_FMODE_MM) { | ||
312 | err = stm32_qspi_wait_cmd(qspi); | ||
313 | if (err) | ||
314 | goto abort; | ||
315 | writel_relaxed(FCR_CTCF, qspi->io_base + QUADSPI_FCR); | ||
316 | } | ||
317 | |||
318 | return err; | ||
319 | |||
320 | abort: | ||
321 | cr = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT; | ||
322 | writel_relaxed(cr, qspi->io_base + QUADSPI_CR); | ||
323 | |||
324 | dev_err(qspi->dev, "%s abort err:%d\n", __func__, err); | ||
325 | return err; | ||
326 | } | ||
327 | |||
328 | static int stm32_qspi_read_reg(struct spi_nor *nor, | ||
329 | u8 opcode, u8 *buf, int len) | ||
330 | { | ||
331 | struct stm32_qspi_flash *flash = nor->priv; | ||
332 | struct device *dev = flash->qspi->dev; | ||
333 | struct stm32_qspi_cmd cmd; | ||
334 | |||
335 | dev_dbg(dev, "read_reg: cmd:%#.2x buf:%p len:%#x\n", opcode, buf, len); | ||
336 | |||
337 | memset(&cmd, 0, sizeof(cmd)); | ||
338 | cmd.opcode = opcode; | ||
339 | cmd.tx_data = true; | ||
340 | cmd.len = len; | ||
341 | cmd.buf = buf; | ||
342 | cmd.qspimode = CCR_FMODE_INDR; | ||
343 | |||
344 | stm32_qspi_set_framemode(nor, &cmd, false); | ||
345 | |||
346 | return stm32_qspi_send(flash, &cmd); | ||
347 | } | ||
348 | |||
349 | static int stm32_qspi_write_reg(struct spi_nor *nor, u8 opcode, | ||
350 | u8 *buf, int len) | ||
351 | { | ||
352 | struct stm32_qspi_flash *flash = nor->priv; | ||
353 | struct device *dev = flash->qspi->dev; | ||
354 | struct stm32_qspi_cmd cmd; | ||
355 | |||
356 | dev_dbg(dev, "write_reg: cmd:%#.2x buf:%p len:%#x\n", opcode, buf, len); | ||
357 | |||
358 | memset(&cmd, 0, sizeof(cmd)); | ||
359 | cmd.opcode = opcode; | ||
360 | cmd.tx_data = !!(buf && len > 0); | ||
361 | cmd.len = len; | ||
362 | cmd.buf = buf; | ||
363 | cmd.qspimode = CCR_FMODE_INDW; | ||
364 | |||
365 | stm32_qspi_set_framemode(nor, &cmd, false); | ||
366 | |||
367 | return stm32_qspi_send(flash, &cmd); | ||
368 | } | ||
369 | |||
370 | static ssize_t stm32_qspi_read(struct spi_nor *nor, loff_t from, size_t len, | ||
371 | u_char *buf) | ||
372 | { | ||
373 | struct stm32_qspi_flash *flash = nor->priv; | ||
374 | struct stm32_qspi *qspi = flash->qspi; | ||
375 | struct stm32_qspi_cmd cmd; | ||
376 | int err; | ||
377 | |||
378 | dev_dbg(qspi->dev, "read(%#.2x): buf:%p from:%#.8x len:%#x\n", | ||
379 | nor->read_opcode, buf, (u32)from, len); | ||
380 | |||
381 | memset(&cmd, 0, sizeof(cmd)); | ||
382 | cmd.opcode = nor->read_opcode; | ||
383 | cmd.addr_width = nor->addr_width; | ||
384 | cmd.addr = (u32)from; | ||
385 | cmd.tx_data = true; | ||
386 | cmd.dummy = nor->read_dummy; | ||
387 | cmd.len = len; | ||
388 | cmd.buf = buf; | ||
389 | cmd.qspimode = flash->read_mode; | ||
390 | |||
391 | stm32_qspi_set_framemode(nor, &cmd, true); | ||
392 | err = stm32_qspi_send(flash, &cmd); | ||
393 | |||
394 | return err ? err : len; | ||
395 | } | ||
396 | |||
397 | static ssize_t stm32_qspi_write(struct spi_nor *nor, loff_t to, size_t len, | ||
398 | const u_char *buf) | ||
399 | { | ||
400 | struct stm32_qspi_flash *flash = nor->priv; | ||
401 | struct device *dev = flash->qspi->dev; | ||
402 | struct stm32_qspi_cmd cmd; | ||
403 | int err; | ||
404 | |||
405 | dev_dbg(dev, "write(%#.2x): buf:%p to:%#.8x len:%#x\n", | ||
406 | nor->program_opcode, buf, (u32)to, len); | ||
407 | |||
408 | memset(&cmd, 0, sizeof(cmd)); | ||
409 | cmd.opcode = nor->program_opcode; | ||
410 | cmd.addr_width = nor->addr_width; | ||
411 | cmd.addr = (u32)to; | ||
412 | cmd.tx_data = true; | ||
413 | cmd.len = len; | ||
414 | cmd.buf = (void *)buf; | ||
415 | cmd.qspimode = CCR_FMODE_INDW; | ||
416 | |||
417 | stm32_qspi_set_framemode(nor, &cmd, false); | ||
418 | err = stm32_qspi_send(flash, &cmd); | ||
419 | |||
420 | return err ? err : len; | ||
421 | } | ||
422 | |||
423 | static int stm32_qspi_erase(struct spi_nor *nor, loff_t offs) | ||
424 | { | ||
425 | struct stm32_qspi_flash *flash = nor->priv; | ||
426 | struct device *dev = flash->qspi->dev; | ||
427 | struct stm32_qspi_cmd cmd; | ||
428 | |||
429 | dev_dbg(dev, "erase(%#.2x):offs:%#x\n", nor->erase_opcode, (u32)offs); | ||
430 | |||
431 | memset(&cmd, 0, sizeof(cmd)); | ||
432 | cmd.opcode = nor->erase_opcode; | ||
433 | cmd.addr_width = nor->addr_width; | ||
434 | cmd.addr = (u32)offs; | ||
435 | cmd.qspimode = CCR_FMODE_INDW; | ||
436 | |||
437 | stm32_qspi_set_framemode(nor, &cmd, false); | ||
438 | |||
439 | return stm32_qspi_send(flash, &cmd); | ||
440 | } | ||
441 | |||
442 | static irqreturn_t stm32_qspi_irq(int irq, void *dev_id) | ||
443 | { | ||
444 | struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id; | ||
445 | u32 cr, sr, fcr = 0; | ||
446 | |||
447 | cr = readl_relaxed(qspi->io_base + QUADSPI_CR); | ||
448 | sr = readl_relaxed(qspi->io_base + QUADSPI_SR); | ||
449 | |||
450 | if ((cr & CR_TCIE) && (sr & SR_TCF)) { | ||
451 | /* tx complete */ | ||
452 | fcr |= FCR_CTCF; | ||
453 | complete(&qspi->cmd_completion); | ||
454 | } else { | ||
455 | dev_info_ratelimited(qspi->dev, "spurious interrupt\n"); | ||
456 | } | ||
457 | |||
458 | writel_relaxed(fcr, qspi->io_base + QUADSPI_FCR); | ||
459 | |||
460 | return IRQ_HANDLED; | ||
461 | } | ||
462 | |||
463 | static int stm32_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) | ||
464 | { | ||
465 | struct stm32_qspi_flash *flash = nor->priv; | ||
466 | struct stm32_qspi *qspi = flash->qspi; | ||
467 | |||
468 | mutex_lock(&qspi->lock); | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static void stm32_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) | ||
473 | { | ||
474 | struct stm32_qspi_flash *flash = nor->priv; | ||
475 | struct stm32_qspi *qspi = flash->qspi; | ||
476 | |||
477 | mutex_unlock(&qspi->lock); | ||
478 | } | ||
479 | |||
480 | static int stm32_qspi_flash_setup(struct stm32_qspi *qspi, | ||
481 | struct device_node *np) | ||
482 | { | ||
483 | u32 width, flash_read, presc, cs_num, max_rate = 0; | ||
484 | struct stm32_qspi_flash *flash; | ||
485 | struct mtd_info *mtd; | ||
486 | int ret; | ||
487 | |||
488 | of_property_read_u32(np, "reg", &cs_num); | ||
489 | if (cs_num >= STM32_MAX_NORCHIP) | ||
490 | return -EINVAL; | ||
491 | |||
492 | of_property_read_u32(np, "spi-max-frequency", &max_rate); | ||
493 | if (!max_rate) | ||
494 | return -EINVAL; | ||
495 | |||
496 | presc = DIV_ROUND_UP(qspi->clk_rate, max_rate) - 1; | ||
497 | |||
498 | if (of_property_read_u32(np, "spi-rx-bus-width", &width)) | ||
499 | width = 1; | ||
500 | |||
501 | if (width == 4) | ||
502 | flash_read = SPI_NOR_QUAD; | ||
503 | else if (width == 2) | ||
504 | flash_read = SPI_NOR_DUAL; | ||
505 | else if (width == 1) | ||
506 | flash_read = SPI_NOR_NORMAL; | ||
507 | else | ||
508 | return -EINVAL; | ||
509 | |||
510 | flash = &qspi->flash[cs_num]; | ||
511 | flash->qspi = qspi; | ||
512 | flash->cs = cs_num; | ||
513 | flash->presc = presc; | ||
514 | |||
515 | flash->nor.dev = qspi->dev; | ||
516 | spi_nor_set_flash_node(&flash->nor, np); | ||
517 | flash->nor.priv = flash; | ||
518 | mtd = &flash->nor.mtd; | ||
519 | |||
520 | flash->nor.read = stm32_qspi_read; | ||
521 | flash->nor.write = stm32_qspi_write; | ||
522 | flash->nor.erase = stm32_qspi_erase; | ||
523 | flash->nor.read_reg = stm32_qspi_read_reg; | ||
524 | flash->nor.write_reg = stm32_qspi_write_reg; | ||
525 | flash->nor.prepare = stm32_qspi_prep; | ||
526 | flash->nor.unprepare = stm32_qspi_unprep; | ||
527 | |||
528 | writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QUADSPI_LPTR); | ||
529 | |||
530 | writel_relaxed(CR_PRESC(presc) | CR_FTHRES(3) | CR_TCEN | CR_SSHIFT | ||
531 | | CR_EN, qspi->io_base + QUADSPI_CR); | ||
532 | |||
533 | /* | ||
534 | * in stm32 qspi controller, QUADSPI_DCR register has a fsize field | ||
535 | * which define the size of nor flash. | ||
536 | * if fsize is NULL, the controller can't sent spi-nor command. | ||
537 | * set a temporary value just to discover the nor flash with | ||
538 | * "spi_nor_scan". After, the right value (mtd->size) can be set. | ||
539 | */ | ||
540 | flash->fsize = FSIZE_VAL(SZ_1K); | ||
541 | |||
542 | ret = spi_nor_scan(&flash->nor, NULL, flash_read); | ||
543 | if (ret) { | ||
544 | dev_err(qspi->dev, "device scan failed\n"); | ||
545 | return ret; | ||
546 | } | ||
547 | |||
548 | flash->fsize = FSIZE_VAL(mtd->size); | ||
549 | |||
550 | flash->read_mode = CCR_FMODE_MM; | ||
551 | if (mtd->size > qspi->mm_size) | ||
552 | flash->read_mode = CCR_FMODE_INDR; | ||
553 | |||
554 | writel_relaxed(DCR_CSHT(1), qspi->io_base + QUADSPI_DCR); | ||
555 | |||
556 | ret = mtd_device_register(mtd, NULL, 0); | ||
557 | if (ret) { | ||
558 | dev_err(qspi->dev, "mtd device parse failed\n"); | ||
559 | return ret; | ||
560 | } | ||
561 | |||
562 | flash->registered = true; | ||
563 | |||
564 | dev_dbg(qspi->dev, "read mm:%s cs:%d bus:%d\n", | ||
565 | flash->read_mode == CCR_FMODE_MM ? "yes" : "no", cs_num, width); | ||
566 | |||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | static void stm32_qspi_mtd_free(struct stm32_qspi *qspi) | ||
571 | { | ||
572 | int i; | ||
573 | |||
574 | for (i = 0; i < STM32_MAX_NORCHIP; i++) | ||
575 | if (qspi->flash[i].registered) | ||
576 | mtd_device_unregister(&qspi->flash[i].nor.mtd); | ||
577 | } | ||
578 | |||
579 | static int stm32_qspi_probe(struct platform_device *pdev) | ||
580 | { | ||
581 | struct device *dev = &pdev->dev; | ||
582 | struct device_node *flash_np; | ||
583 | struct reset_control *rstc; | ||
584 | struct stm32_qspi *qspi; | ||
585 | struct resource *res; | ||
586 | int ret, irq; | ||
587 | |||
588 | qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL); | ||
589 | if (!qspi) | ||
590 | return -ENOMEM; | ||
591 | |||
592 | qspi->nor_num = of_get_child_count(dev->of_node); | ||
593 | if (!qspi->nor_num || qspi->nor_num > STM32_MAX_NORCHIP) | ||
594 | return -ENODEV; | ||
595 | |||
596 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi"); | ||
597 | qspi->io_base = devm_ioremap_resource(dev, res); | ||
598 | if (IS_ERR(qspi->io_base)) | ||
599 | return PTR_ERR(qspi->io_base); | ||
600 | |||
601 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm"); | ||
602 | qspi->mm_base = devm_ioremap_resource(dev, res); | ||
603 | if (IS_ERR(qspi->mm_base)) | ||
604 | return PTR_ERR(qspi->mm_base); | ||
605 | |||
606 | qspi->mm_size = resource_size(res); | ||
607 | |||
608 | irq = platform_get_irq(pdev, 0); | ||
609 | ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0, | ||
610 | dev_name(dev), qspi); | ||
611 | if (ret) { | ||
612 | dev_err(dev, "failed to request irq\n"); | ||
613 | return ret; | ||
614 | } | ||
615 | |||
616 | init_completion(&qspi->cmd_completion); | ||
617 | |||
618 | qspi->clk = devm_clk_get(dev, NULL); | ||
619 | if (IS_ERR(qspi->clk)) | ||
620 | return PTR_ERR(qspi->clk); | ||
621 | |||
622 | qspi->clk_rate = clk_get_rate(qspi->clk); | ||
623 | if (!qspi->clk_rate) | ||
624 | return -EINVAL; | ||
625 | |||
626 | ret = clk_prepare_enable(qspi->clk); | ||
627 | if (ret) { | ||
628 | dev_err(dev, "can not enable the clock\n"); | ||
629 | return ret; | ||
630 | } | ||
631 | |||
632 | rstc = devm_reset_control_get(dev, NULL); | ||
633 | if (!IS_ERR(rstc)) { | ||
634 | reset_control_assert(rstc); | ||
635 | udelay(2); | ||
636 | reset_control_deassert(rstc); | ||
637 | } | ||
638 | |||
639 | qspi->dev = dev; | ||
640 | platform_set_drvdata(pdev, qspi); | ||
641 | mutex_init(&qspi->lock); | ||
642 | |||
643 | for_each_available_child_of_node(dev->of_node, flash_np) { | ||
644 | ret = stm32_qspi_flash_setup(qspi, flash_np); | ||
645 | if (ret) { | ||
646 | dev_err(dev, "unable to setup flash chip\n"); | ||
647 | goto err_flash; | ||
648 | } | ||
649 | } | ||
650 | |||
651 | return 0; | ||
652 | |||
653 | err_flash: | ||
654 | mutex_destroy(&qspi->lock); | ||
655 | stm32_qspi_mtd_free(qspi); | ||
656 | |||
657 | clk_disable_unprepare(qspi->clk); | ||
658 | return ret; | ||
659 | } | ||
660 | |||
661 | static int stm32_qspi_remove(struct platform_device *pdev) | ||
662 | { | ||
663 | struct stm32_qspi *qspi = platform_get_drvdata(pdev); | ||
664 | |||
665 | /* disable qspi */ | ||
666 | writel_relaxed(0, qspi->io_base + QUADSPI_CR); | ||
667 | |||
668 | stm32_qspi_mtd_free(qspi); | ||
669 | mutex_destroy(&qspi->lock); | ||
670 | |||
671 | clk_disable_unprepare(qspi->clk); | ||
672 | return 0; | ||
673 | } | ||
674 | |||
675 | static const struct of_device_id stm32_qspi_match[] = { | ||
676 | {.compatible = "st,stm32f469-qspi"}, | ||
677 | {} | ||
678 | }; | ||
679 | MODULE_DEVICE_TABLE(of, stm32_qspi_match); | ||
680 | |||
681 | static struct platform_driver stm32_qspi_driver = { | ||
682 | .probe = stm32_qspi_probe, | ||
683 | .remove = stm32_qspi_remove, | ||
684 | .driver = { | ||
685 | .name = "stm32-quadspi", | ||
686 | .of_match_table = stm32_qspi_match, | ||
687 | }, | ||
688 | }; | ||
689 | module_platform_driver(stm32_qspi_driver); | ||
690 | |||
691 | MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>"); | ||
692 | MODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver"); | ||
693 | MODULE_LICENSE("GPL v2"); | ||