xref: /openbmc/u-boot/drivers/spi/stm32_qspi.c (revision 50e24381c097579ff2a8b171838347c82c2fba04)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2d4363baaSMichael Kurz /*
3d4363baaSMichael Kurz  * (C) Copyright 2016
4d4363baaSMichael Kurz  *
5d4363baaSMichael Kurz  * Michael Kurz, <michi.kurz@gmail.com>
6d4363baaSMichael Kurz  *
7d4363baaSMichael Kurz  * STM32 QSPI driver
8d4363baaSMichael Kurz  */
9d4363baaSMichael Kurz 
10d4363baaSMichael Kurz #include <common.h>
118c4592d2SPatrice Chotard #include <clk.h>
128c4592d2SPatrice Chotard #include <dm.h>
138c4592d2SPatrice Chotard #include <errno.h>
14d4363baaSMichael Kurz #include <malloc.h>
155e46123bSPatrice Chotard #include <reset.h>
16d4363baaSMichael Kurz #include <spi.h>
17d4363baaSMichael Kurz #include <spi_flash.h>
18d4363baaSMichael Kurz #include <asm/io.h>
19d4363baaSMichael Kurz #include <asm/arch/stm32.h>
202a6ca736SPatrice Chotard #include <linux/ioport.h>
21d4363baaSMichael Kurz 
22d4363baaSMichael Kurz struct stm32_qspi_regs {
23d4363baaSMichael Kurz 	u32 cr;		/* 0x00 */
24d4363baaSMichael Kurz 	u32 dcr;	/* 0x04 */
25d4363baaSMichael Kurz 	u32 sr;		/* 0x08 */
26d4363baaSMichael Kurz 	u32 fcr;	/* 0x0C */
27d4363baaSMichael Kurz 	u32 dlr;	/* 0x10 */
28d4363baaSMichael Kurz 	u32 ccr;	/* 0x14 */
29d4363baaSMichael Kurz 	u32 ar;		/* 0x18 */
30d4363baaSMichael Kurz 	u32 abr;	/* 0x1C */
31d4363baaSMichael Kurz 	u32 dr;		/* 0x20 */
32d4363baaSMichael Kurz 	u32 psmkr;	/* 0x24 */
33d4363baaSMichael Kurz 	u32 psmar;	/* 0x28 */
34d4363baaSMichael Kurz 	u32 pir;	/* 0x2C */
35d4363baaSMichael Kurz 	u32 lptr;	/* 0x30 */
36d4363baaSMichael Kurz };
37d4363baaSMichael Kurz 
38d4363baaSMichael Kurz /*
39d4363baaSMichael Kurz  * QUADSPI control register
40d4363baaSMichael Kurz  */
41d4363baaSMichael Kurz #define STM32_QSPI_CR_EN		BIT(0)
42d4363baaSMichael Kurz #define STM32_QSPI_CR_ABORT		BIT(1)
43d4363baaSMichael Kurz #define STM32_QSPI_CR_DMAEN		BIT(2)
44d4363baaSMichael Kurz #define STM32_QSPI_CR_TCEN		BIT(3)
45d4363baaSMichael Kurz #define STM32_QSPI_CR_SSHIFT		BIT(4)
46d4363baaSMichael Kurz #define STM32_QSPI_CR_DFM		BIT(6)
47d4363baaSMichael Kurz #define STM32_QSPI_CR_FSEL		BIT(7)
48d4363baaSMichael Kurz #define STM32_QSPI_CR_FTHRES_MASK	GENMASK(4, 0)
49d4363baaSMichael Kurz #define STM32_QSPI_CR_FTHRES_SHIFT	(8)
50d4363baaSMichael Kurz #define STM32_QSPI_CR_TEIE		BIT(16)
51d4363baaSMichael Kurz #define STM32_QSPI_CR_TCIE		BIT(17)
52d4363baaSMichael Kurz #define STM32_QSPI_CR_FTIE		BIT(18)
53d4363baaSMichael Kurz #define STM32_QSPI_CR_SMIE		BIT(19)
54d4363baaSMichael Kurz #define STM32_QSPI_CR_TOIE		BIT(20)
55d4363baaSMichael Kurz #define STM32_QSPI_CR_APMS		BIT(22)
56d4363baaSMichael Kurz #define STM32_QSPI_CR_PMM		BIT(23)
57d4363baaSMichael Kurz #define STM32_QSPI_CR_PRESCALER_MASK	GENMASK(7, 0)
58d4363baaSMichael Kurz #define STM32_QSPI_CR_PRESCALER_SHIFT	(24)
59d4363baaSMichael Kurz 
60d4363baaSMichael Kurz /*
61d4363baaSMichael Kurz  * QUADSPI device configuration register
62d4363baaSMichael Kurz  */
63d4363baaSMichael Kurz #define STM32_QSPI_DCR_CKMODE		BIT(0)
64d4363baaSMichael Kurz #define STM32_QSPI_DCR_CSHT_MASK	GENMASK(2, 0)
65d4363baaSMichael Kurz #define STM32_QSPI_DCR_CSHT_SHIFT	(8)
66d4363baaSMichael Kurz #define STM32_QSPI_DCR_FSIZE_MASK	GENMASK(4, 0)
67d4363baaSMichael Kurz #define STM32_QSPI_DCR_FSIZE_SHIFT	(16)
68d4363baaSMichael Kurz 
69d4363baaSMichael Kurz /*
70d4363baaSMichael Kurz  * QUADSPI status register
71d4363baaSMichael Kurz  */
72d4363baaSMichael Kurz #define STM32_QSPI_SR_TEF		BIT(0)
73d4363baaSMichael Kurz #define STM32_QSPI_SR_TCF		BIT(1)
74d4363baaSMichael Kurz #define STM32_QSPI_SR_FTF		BIT(2)
75d4363baaSMichael Kurz #define STM32_QSPI_SR_SMF		BIT(3)
76d4363baaSMichael Kurz #define STM32_QSPI_SR_TOF		BIT(4)
77d4363baaSMichael Kurz #define STM32_QSPI_SR_BUSY		BIT(5)
78d4363baaSMichael Kurz #define STM32_QSPI_SR_FLEVEL_MASK	GENMASK(5, 0)
79d4363baaSMichael Kurz #define STM32_QSPI_SR_FLEVEL_SHIFT	(8)
80d4363baaSMichael Kurz 
81d4363baaSMichael Kurz /*
82d4363baaSMichael Kurz  * QUADSPI flag clear register
83d4363baaSMichael Kurz  */
84d4363baaSMichael Kurz #define STM32_QSPI_FCR_CTEF		BIT(0)
85d4363baaSMichael Kurz #define STM32_QSPI_FCR_CTCF		BIT(1)
86d4363baaSMichael Kurz #define STM32_QSPI_FCR_CSMF		BIT(3)
87d4363baaSMichael Kurz #define STM32_QSPI_FCR_CTOF		BIT(4)
88d4363baaSMichael Kurz 
89d4363baaSMichael Kurz /*
90d4363baaSMichael Kurz  * QUADSPI communication configuration register
91d4363baaSMichael Kurz  */
92d4363baaSMichael Kurz #define STM32_QSPI_CCR_DDRM		BIT(31)
93d4363baaSMichael Kurz #define STM32_QSPI_CCR_DHHC		BIT(30)
94d4363baaSMichael Kurz #define STM32_QSPI_CCR_SIOO		BIT(28)
95d4363baaSMichael Kurz #define STM32_QSPI_CCR_FMODE_SHIFT	(26)
96d4363baaSMichael Kurz #define STM32_QSPI_CCR_DMODE_SHIFT	(24)
97d4363baaSMichael Kurz #define STM32_QSPI_CCR_DCYC_SHIFT	(18)
98d4363baaSMichael Kurz #define STM32_QSPI_CCR_DCYC_MASK	GENMASK(4, 0)
99d4363baaSMichael Kurz #define STM32_QSPI_CCR_ABSIZE_SHIFT	(16)
100d4363baaSMichael Kurz #define STM32_QSPI_CCR_ABMODE_SHIFT	(14)
101d4363baaSMichael Kurz #define STM32_QSPI_CCR_ADSIZE_SHIFT	(12)
102d4363baaSMichael Kurz #define STM32_QSPI_CCR_ADMODE_SHIFT	(10)
103d4363baaSMichael Kurz #define STM32_QSPI_CCR_IMODE_SHIFT	(8)
104d4363baaSMichael Kurz #define STM32_QSPI_CCR_INSTRUCTION_MASK	GENMASK(7, 0)
105d4363baaSMichael Kurz 
106d4363baaSMichael Kurz enum STM32_QSPI_CCR_IMODE {
107d4363baaSMichael Kurz 	STM32_QSPI_CCR_IMODE_NONE = 0,
108d4363baaSMichael Kurz 	STM32_QSPI_CCR_IMODE_ONE_LINE = 1,
109d4363baaSMichael Kurz 	STM32_QSPI_CCR_IMODE_TWO_LINE = 2,
110d4363baaSMichael Kurz 	STM32_QSPI_CCR_IMODE_FOUR_LINE = 3,
111d4363baaSMichael Kurz };
112d4363baaSMichael Kurz 
113d4363baaSMichael Kurz enum STM32_QSPI_CCR_ADMODE {
114d4363baaSMichael Kurz 	STM32_QSPI_CCR_ADMODE_NONE = 0,
115d4363baaSMichael Kurz 	STM32_QSPI_CCR_ADMODE_ONE_LINE = 1,
116d4363baaSMichael Kurz 	STM32_QSPI_CCR_ADMODE_TWO_LINE = 2,
117d4363baaSMichael Kurz 	STM32_QSPI_CCR_ADMODE_FOUR_LINE = 3,
118d4363baaSMichael Kurz };
119d4363baaSMichael Kurz 
120d4363baaSMichael Kurz enum STM32_QSPI_CCR_ADSIZE {
121d4363baaSMichael Kurz 	STM32_QSPI_CCR_ADSIZE_8BIT = 0,
122d4363baaSMichael Kurz 	STM32_QSPI_CCR_ADSIZE_16BIT = 1,
123d4363baaSMichael Kurz 	STM32_QSPI_CCR_ADSIZE_24BIT = 2,
124d4363baaSMichael Kurz 	STM32_QSPI_CCR_ADSIZE_32BIT = 3,
125d4363baaSMichael Kurz };
126d4363baaSMichael Kurz 
127d4363baaSMichael Kurz enum STM32_QSPI_CCR_ABMODE {
128d4363baaSMichael Kurz 	STM32_QSPI_CCR_ABMODE_NONE = 0,
129d4363baaSMichael Kurz 	STM32_QSPI_CCR_ABMODE_ONE_LINE = 1,
130d4363baaSMichael Kurz 	STM32_QSPI_CCR_ABMODE_TWO_LINE = 2,
131d4363baaSMichael Kurz 	STM32_QSPI_CCR_ABMODE_FOUR_LINE = 3,
132d4363baaSMichael Kurz };
133d4363baaSMichael Kurz 
134d4363baaSMichael Kurz enum STM32_QSPI_CCR_ABSIZE {
135d4363baaSMichael Kurz 	STM32_QSPI_CCR_ABSIZE_8BIT = 0,
136d4363baaSMichael Kurz 	STM32_QSPI_CCR_ABSIZE_16BIT = 1,
137d4363baaSMichael Kurz 	STM32_QSPI_CCR_ABSIZE_24BIT = 2,
138d4363baaSMichael Kurz 	STM32_QSPI_CCR_ABSIZE_32BIT = 3,
139d4363baaSMichael Kurz };
140d4363baaSMichael Kurz 
141d4363baaSMichael Kurz enum STM32_QSPI_CCR_DMODE {
142d4363baaSMichael Kurz 	STM32_QSPI_CCR_DMODE_NONE = 0,
143d4363baaSMichael Kurz 	STM32_QSPI_CCR_DMODE_ONE_LINE = 1,
144d4363baaSMichael Kurz 	STM32_QSPI_CCR_DMODE_TWO_LINE = 2,
145d4363baaSMichael Kurz 	STM32_QSPI_CCR_DMODE_FOUR_LINE = 3,
146d4363baaSMichael Kurz };
147d4363baaSMichael Kurz 
148d4363baaSMichael Kurz enum STM32_QSPI_CCR_FMODE {
149d4363baaSMichael Kurz 	STM32_QSPI_CCR_IND_WRITE = 0,
150d4363baaSMichael Kurz 	STM32_QSPI_CCR_IND_READ = 1,
151d4363baaSMichael Kurz 	STM32_QSPI_CCR_AUTO_POLL = 2,
152d4363baaSMichael Kurz 	STM32_QSPI_CCR_MEM_MAP = 3,
153d4363baaSMichael Kurz };
154d4363baaSMichael Kurz 
155d4363baaSMichael Kurz /* default SCK frequency, unit: HZ */
156d4363baaSMichael Kurz #define STM32_QSPI_DEFAULT_SCK_FREQ 108000000
157d4363baaSMichael Kurz 
158495f3b2aSChristophe Kerello #define STM32_MAX_NORCHIP 2
159495f3b2aSChristophe Kerello 
160d4363baaSMichael Kurz struct stm32_qspi_platdata {
161d4363baaSMichael Kurz 	u32 base;
162d4363baaSMichael Kurz 	u32 memory_map;
163d4363baaSMichael Kurz 	u32 max_hz;
164d4363baaSMichael Kurz };
165d4363baaSMichael Kurz 
166d4363baaSMichael Kurz struct stm32_qspi_priv {
167d4363baaSMichael Kurz 	struct stm32_qspi_regs *regs;
168541cd6e5SPatrice Chotard 	ulong clock_rate;
169d4363baaSMichael Kurz 	u32 max_hz;
170d4363baaSMichael Kurz 	u32 mode;
171d4363baaSMichael Kurz 
172d4363baaSMichael Kurz 	u32 command;
173d4363baaSMichael Kurz 	u32 address;
174d4363baaSMichael Kurz 	u32 dummycycles;
175d4363baaSMichael Kurz #define CMD_HAS_ADR	BIT(24)
176d4363baaSMichael Kurz #define CMD_HAS_DUMMY	BIT(25)
177d4363baaSMichael Kurz #define CMD_HAS_DATA	BIT(26)
178d4363baaSMichael Kurz };
179d4363baaSMichael Kurz 
_stm32_qspi_disable(struct stm32_qspi_priv * priv)180d4363baaSMichael Kurz static void _stm32_qspi_disable(struct stm32_qspi_priv *priv)
181d4363baaSMichael Kurz {
182d4363baaSMichael Kurz 	clrbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN);
183d4363baaSMichael Kurz }
184d4363baaSMichael Kurz 
_stm32_qspi_enable(struct stm32_qspi_priv * priv)185d4363baaSMichael Kurz static void _stm32_qspi_enable(struct stm32_qspi_priv *priv)
186d4363baaSMichael Kurz {
187d4363baaSMichael Kurz 	setbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN);
188d4363baaSMichael Kurz }
189d4363baaSMichael Kurz 
_stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv * priv)190d4363baaSMichael Kurz static void _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv)
191d4363baaSMichael Kurz {
192d4363baaSMichael Kurz 	while (readl(&priv->regs->sr) & STM32_QSPI_SR_BUSY)
193d4363baaSMichael Kurz 		;
194d4363baaSMichael Kurz }
195d4363baaSMichael Kurz 
_stm32_qspi_wait_for_complete(struct stm32_qspi_priv * priv)196d4363baaSMichael Kurz static void _stm32_qspi_wait_for_complete(struct stm32_qspi_priv *priv)
197d4363baaSMichael Kurz {
198d4363baaSMichael Kurz 	while (!(readl(&priv->regs->sr) & STM32_QSPI_SR_TCF))
199d4363baaSMichael Kurz 		;
200d4363baaSMichael Kurz }
201d4363baaSMichael Kurz 
_stm32_qspi_wait_for_ftf(struct stm32_qspi_priv * priv)202d4363baaSMichael Kurz static void _stm32_qspi_wait_for_ftf(struct stm32_qspi_priv *priv)
203d4363baaSMichael Kurz {
204d4363baaSMichael Kurz 	while (!(readl(&priv->regs->sr) & STM32_QSPI_SR_FTF))
205d4363baaSMichael Kurz 		;
206d4363baaSMichael Kurz }
207d4363baaSMichael Kurz 
_stm32_qspi_set_flash_size(struct stm32_qspi_priv * priv,u32 size)208d4363baaSMichael Kurz static void _stm32_qspi_set_flash_size(struct stm32_qspi_priv *priv, u32 size)
209d4363baaSMichael Kurz {
210d4363baaSMichael Kurz 	u32 fsize = fls(size) - 1;
211936abadaSPatrick Delaunay 
212d4363baaSMichael Kurz 	clrsetbits_le32(&priv->regs->dcr,
213d4363baaSMichael Kurz 			STM32_QSPI_DCR_FSIZE_MASK << STM32_QSPI_DCR_FSIZE_SHIFT,
214d4363baaSMichael Kurz 			fsize << STM32_QSPI_DCR_FSIZE_SHIFT);
215d4363baaSMichael Kurz }
216d4363baaSMichael Kurz 
_stm32_qspi_set_cs(struct stm32_qspi_priv * priv,unsigned int cs)217495f3b2aSChristophe Kerello static void _stm32_qspi_set_cs(struct stm32_qspi_priv *priv, unsigned int cs)
218495f3b2aSChristophe Kerello {
219495f3b2aSChristophe Kerello 	clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_FSEL,
220495f3b2aSChristophe Kerello 			cs ? STM32_QSPI_CR_FSEL : 0);
221495f3b2aSChristophe Kerello }
222495f3b2aSChristophe Kerello 
_stm32_qspi_gen_ccr(struct stm32_qspi_priv * priv,u8 fmode)223ceff933eSChristophe Kerello static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv, u8 fmode)
224d4363baaSMichael Kurz {
225d4363baaSMichael Kurz 	unsigned int ccr_reg = 0;
226d4363baaSMichael Kurz 	u8 imode, admode, dmode;
227d4363baaSMichael Kurz 	u32 mode = priv->mode;
228d4363baaSMichael Kurz 	u32 cmd = (priv->command & STM32_QSPI_CCR_INSTRUCTION_MASK);
229d4363baaSMichael Kurz 
230d4363baaSMichael Kurz 	imode = STM32_QSPI_CCR_IMODE_ONE_LINE;
231d4363baaSMichael Kurz 	admode = STM32_QSPI_CCR_ADMODE_ONE_LINE;
232d4363baaSMichael Kurz 	dmode = STM32_QSPI_CCR_DMODE_ONE_LINE;
233d68b6ad1SChristophe Kerello 
234d68b6ad1SChristophe Kerello 	if ((priv->command & CMD_HAS_ADR) && (priv->command & CMD_HAS_DATA)) {
235d68b6ad1SChristophe Kerello 		if (fmode == STM32_QSPI_CCR_IND_WRITE) {
236d68b6ad1SChristophe Kerello 			if (mode & SPI_TX_QUAD)
237d68b6ad1SChristophe Kerello 				dmode = STM32_QSPI_CCR_DMODE_FOUR_LINE;
238d68b6ad1SChristophe Kerello 			else if (mode & SPI_TX_DUAL)
239d68b6ad1SChristophe Kerello 				dmode = STM32_QSPI_CCR_DMODE_TWO_LINE;
240d68b6ad1SChristophe Kerello 		} else if ((fmode == STM32_QSPI_CCR_MEM_MAP) ||
241d68b6ad1SChristophe Kerello 			 (fmode == STM32_QSPI_CCR_IND_READ)) {
242d68b6ad1SChristophe Kerello 			if (mode & SPI_RX_QUAD)
243d68b6ad1SChristophe Kerello 				dmode = STM32_QSPI_CCR_DMODE_FOUR_LINE;
244d68b6ad1SChristophe Kerello 			else if (mode & SPI_RX_DUAL)
245d68b6ad1SChristophe Kerello 				dmode = STM32_QSPI_CCR_DMODE_TWO_LINE;
246d68b6ad1SChristophe Kerello 		}
247d4363baaSMichael Kurz 	}
248d4363baaSMichael Kurz 
249d4363baaSMichael Kurz 	if (priv->command & CMD_HAS_DATA)
250d4363baaSMichael Kurz 		ccr_reg |= (dmode << STM32_QSPI_CCR_DMODE_SHIFT);
251d4363baaSMichael Kurz 
252d4363baaSMichael Kurz 	if (priv->command & CMD_HAS_DUMMY)
253d4363baaSMichael Kurz 		ccr_reg |= ((priv->dummycycles & STM32_QSPI_CCR_DCYC_MASK)
254d4363baaSMichael Kurz 				<< STM32_QSPI_CCR_DCYC_SHIFT);
255d4363baaSMichael Kurz 
256d4363baaSMichael Kurz 	if (priv->command & CMD_HAS_ADR) {
257d4363baaSMichael Kurz 		ccr_reg |= (STM32_QSPI_CCR_ADSIZE_24BIT
258d4363baaSMichael Kurz 				<< STM32_QSPI_CCR_ADSIZE_SHIFT);
259d4363baaSMichael Kurz 		ccr_reg |= (admode << STM32_QSPI_CCR_ADMODE_SHIFT);
260d4363baaSMichael Kurz 	}
261ceff933eSChristophe Kerello 
262ceff933eSChristophe Kerello 	ccr_reg |= (fmode << STM32_QSPI_CCR_FMODE_SHIFT);
263d4363baaSMichael Kurz 	ccr_reg |= (imode << STM32_QSPI_CCR_IMODE_SHIFT);
264d4363baaSMichael Kurz 	ccr_reg |= cmd;
265ceff933eSChristophe Kerello 
266d4363baaSMichael Kurz 	return ccr_reg;
267d4363baaSMichael Kurz }
268d4363baaSMichael Kurz 
_stm32_qspi_enable_mmap(struct stm32_qspi_priv * priv,struct spi_flash * flash)269d4363baaSMichael Kurz static void _stm32_qspi_enable_mmap(struct stm32_qspi_priv *priv,
270d4363baaSMichael Kurz 				    struct spi_flash *flash)
271d4363baaSMichael Kurz {
272936abadaSPatrick Delaunay 	unsigned int ccr_reg;
273936abadaSPatrick Delaunay 
274*c4e88623SVignesh R 	priv->command = flash->read_opcode | CMD_HAS_ADR | CMD_HAS_DATA
275d4363baaSMichael Kurz 			| CMD_HAS_DUMMY;
276*c4e88623SVignesh R 	priv->dummycycles = flash->read_dummy;
277d4363baaSMichael Kurz 
278ceff933eSChristophe Kerello 	ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_MEM_MAP);
279d4363baaSMichael Kurz 
280d4363baaSMichael Kurz 	_stm32_qspi_wait_for_not_busy(priv);
281d4363baaSMichael Kurz 
282d4363baaSMichael Kurz 	writel(ccr_reg, &priv->regs->ccr);
283d4363baaSMichael Kurz 
284d4363baaSMichael Kurz 	priv->dummycycles = 0;
285d4363baaSMichael Kurz }
286d4363baaSMichael Kurz 
_stm32_qspi_disable_mmap(struct stm32_qspi_priv * priv)287d4363baaSMichael Kurz static void _stm32_qspi_disable_mmap(struct stm32_qspi_priv *priv)
288d4363baaSMichael Kurz {
289d4363baaSMichael Kurz 	setbits_le32(&priv->regs->cr, STM32_QSPI_CR_ABORT);
290d4363baaSMichael Kurz }
291d4363baaSMichael Kurz 
_stm32_qspi_set_xfer_length(struct stm32_qspi_priv * priv,u32 length)292d4363baaSMichael Kurz static void _stm32_qspi_set_xfer_length(struct stm32_qspi_priv *priv,
293d4363baaSMichael Kurz 					u32 length)
294d4363baaSMichael Kurz {
295d4363baaSMichael Kurz 	writel(length - 1, &priv->regs->dlr);
296d4363baaSMichael Kurz }
297d4363baaSMichael Kurz 
_stm32_qspi_start_xfer(struct stm32_qspi_priv * priv,u32 cr_reg)298d4363baaSMichael Kurz static void _stm32_qspi_start_xfer(struct stm32_qspi_priv *priv, u32 cr_reg)
299d4363baaSMichael Kurz {
300d4363baaSMichael Kurz 	writel(cr_reg, &priv->regs->ccr);
301d4363baaSMichael Kurz 
302d4363baaSMichael Kurz 	if (priv->command & CMD_HAS_ADR)
303d4363baaSMichael Kurz 		writel(priv->address, &priv->regs->ar);
304d4363baaSMichael Kurz }
305d4363baaSMichael Kurz 
_stm32_qspi_xfer(struct stm32_qspi_priv * priv,struct spi_flash * flash,unsigned int bitlen,const u8 * dout,u8 * din,unsigned long flags)306d4363baaSMichael Kurz static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv,
307d4363baaSMichael Kurz 			    struct spi_flash *flash, unsigned int bitlen,
308d4363baaSMichael Kurz 			    const u8 *dout, u8 *din, unsigned long flags)
309d4363baaSMichael Kurz {
310d4363baaSMichael Kurz 	unsigned int words = bitlen / 8;
311936abadaSPatrick Delaunay 	u32 ccr_reg;
312936abadaSPatrick Delaunay 	int i;
313d4363baaSMichael Kurz 
314d4363baaSMichael Kurz 	if (flags & SPI_XFER_MMAP) {
315d4363baaSMichael Kurz 		_stm32_qspi_enable_mmap(priv, flash);
316d4363baaSMichael Kurz 		return 0;
317d4363baaSMichael Kurz 	} else if (flags & SPI_XFER_MMAP_END) {
318d4363baaSMichael Kurz 		_stm32_qspi_disable_mmap(priv);
319d4363baaSMichael Kurz 		return 0;
320d4363baaSMichael Kurz 	}
321d4363baaSMichael Kurz 
322d4363baaSMichael Kurz 	if (bitlen == 0)
323d4363baaSMichael Kurz 		return -1;
324d4363baaSMichael Kurz 
325d4363baaSMichael Kurz 	if (bitlen % 8) {
326d4363baaSMichael Kurz 		debug("spi_xfer: Non byte aligned SPI transfer\n");
327d4363baaSMichael Kurz 		return -1;
328d4363baaSMichael Kurz 	}
329d4363baaSMichael Kurz 
330d4363baaSMichael Kurz 	if (dout && din) {
331d4363baaSMichael Kurz 		debug("spi_xfer: QSPI cannot have data in and data out set\n");
332d4363baaSMichael Kurz 		return -1;
333d4363baaSMichael Kurz 	}
334d4363baaSMichael Kurz 
335d4363baaSMichael Kurz 	if (!dout && (flags & SPI_XFER_BEGIN)) {
336d4363baaSMichael Kurz 		debug("spi_xfer: QSPI transfer must begin with command\n");
337d4363baaSMichael Kurz 		return -1;
338d4363baaSMichael Kurz 	}
339d4363baaSMichael Kurz 
340d4363baaSMichael Kurz 	if (dout) {
341d4363baaSMichael Kurz 		if (flags & SPI_XFER_BEGIN) {
342d4363baaSMichael Kurz 			/* data is command */
343d4363baaSMichael Kurz 			priv->command = dout[0] | CMD_HAS_DATA;
344d4363baaSMichael Kurz 			if (words >= 4) {
345d4363baaSMichael Kurz 				/* address is here too */
346d4363baaSMichael Kurz 				priv->address = (dout[1] << 16) |
347d4363baaSMichael Kurz 						(dout[2] << 8) | dout[3];
348d4363baaSMichael Kurz 				priv->command |= CMD_HAS_ADR;
349d4363baaSMichael Kurz 			}
350d4363baaSMichael Kurz 
351d4363baaSMichael Kurz 			if (words > 4) {
352d4363baaSMichael Kurz 				/* rest is dummy bytes */
353d4363baaSMichael Kurz 				priv->dummycycles = (words - 4) * 8;
354d4363baaSMichael Kurz 				priv->command |= CMD_HAS_DUMMY;
355d4363baaSMichael Kurz 			}
356d4363baaSMichael Kurz 
357d4363baaSMichael Kurz 			if (flags & SPI_XFER_END) {
358d4363baaSMichael Kurz 				/* command without data */
359d4363baaSMichael Kurz 				priv->command &= ~(CMD_HAS_DATA);
360d4363baaSMichael Kurz 			}
361d4363baaSMichael Kurz 		}
362d4363baaSMichael Kurz 
363d4363baaSMichael Kurz 		if (flags & SPI_XFER_END) {
364ceff933eSChristophe Kerello 			ccr_reg = _stm32_qspi_gen_ccr(priv,
365ceff933eSChristophe Kerello 						      STM32_QSPI_CCR_IND_WRITE);
366d4363baaSMichael Kurz 
367d4363baaSMichael Kurz 			_stm32_qspi_wait_for_not_busy(priv);
368d4363baaSMichael Kurz 
369d4363baaSMichael Kurz 			if (priv->command & CMD_HAS_DATA)
370d4363baaSMichael Kurz 				_stm32_qspi_set_xfer_length(priv, words);
371d4363baaSMichael Kurz 
372d4363baaSMichael Kurz 			_stm32_qspi_start_xfer(priv, ccr_reg);
373d4363baaSMichael Kurz 
374d4363baaSMichael Kurz 			debug("%s: write: ccr:0x%08x adr:0x%08x\n",
375d4363baaSMichael Kurz 			      __func__, priv->regs->ccr, priv->regs->ar);
376d4363baaSMichael Kurz 
377d4363baaSMichael Kurz 			if (priv->command & CMD_HAS_DATA) {
378d4363baaSMichael Kurz 				_stm32_qspi_wait_for_ftf(priv);
379d4363baaSMichael Kurz 
380d4363baaSMichael Kurz 				debug("%s: words:%d data:", __func__, words);
381d4363baaSMichael Kurz 
382936abadaSPatrick Delaunay 				i = 0;
383d4363baaSMichael Kurz 				while (words > i) {
384d4363baaSMichael Kurz 					writeb(dout[i], &priv->regs->dr);
385d4363baaSMichael Kurz 					debug("%02x ", dout[i]);
386d4363baaSMichael Kurz 					i++;
387d4363baaSMichael Kurz 				}
388d4363baaSMichael Kurz 				debug("\n");
389d4363baaSMichael Kurz 
390d4363baaSMichael Kurz 				_stm32_qspi_wait_for_complete(priv);
391d4363baaSMichael Kurz 			} else {
392d4363baaSMichael Kurz 				_stm32_qspi_wait_for_not_busy(priv);
393d4363baaSMichael Kurz 			}
394d4363baaSMichael Kurz 		}
395d4363baaSMichael Kurz 	} else if (din) {
396ceff933eSChristophe Kerello 		ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_IND_READ);
397d4363baaSMichael Kurz 
398d4363baaSMichael Kurz 		_stm32_qspi_wait_for_not_busy(priv);
399d4363baaSMichael Kurz 
400d4363baaSMichael Kurz 		_stm32_qspi_set_xfer_length(priv, words);
401d4363baaSMichael Kurz 
402d4363baaSMichael Kurz 		_stm32_qspi_start_xfer(priv, ccr_reg);
403d4363baaSMichael Kurz 
404d4363baaSMichael Kurz 		debug("%s: read: ccr:0x%08x adr:0x%08x len:%d\n", __func__,
405d4363baaSMichael Kurz 		      priv->regs->ccr, priv->regs->ar, priv->regs->dlr);
406d4363baaSMichael Kurz 
407d4363baaSMichael Kurz 		debug("%s: data:", __func__);
408d4363baaSMichael Kurz 
409936abadaSPatrick Delaunay 		i = 0;
410d4363baaSMichael Kurz 		while (words > i) {
411d4363baaSMichael Kurz 			din[i] = readb(&priv->regs->dr);
412d4363baaSMichael Kurz 			debug("%02x ", din[i]);
413d4363baaSMichael Kurz 			i++;
414d4363baaSMichael Kurz 		}
415d4363baaSMichael Kurz 		debug("\n");
416d4363baaSMichael Kurz 	}
417d4363baaSMichael Kurz 
418d4363baaSMichael Kurz 	return 0;
419d4363baaSMichael Kurz }
420d4363baaSMichael Kurz 
stm32_qspi_ofdata_to_platdata(struct udevice * bus)421d4363baaSMichael Kurz static int stm32_qspi_ofdata_to_platdata(struct udevice *bus)
422d4363baaSMichael Kurz {
4232a6ca736SPatrice Chotard 	struct resource res_regs, res_mem;
424d4363baaSMichael Kurz 	struct stm32_qspi_platdata *plat = bus->platdata;
425d4363baaSMichael Kurz 	int ret;
426d4363baaSMichael Kurz 
4272a6ca736SPatrice Chotard 	ret = dev_read_resource_byname(bus, "qspi", &res_regs);
428d4363baaSMichael Kurz 	if (ret) {
429d4363baaSMichael Kurz 		debug("Error: can't get regs base addresses(ret = %d)!\n", ret);
430d4363baaSMichael Kurz 		return -ENOMEM;
431d4363baaSMichael Kurz 	}
4322a6ca736SPatrice Chotard 	ret = dev_read_resource_byname(bus, "qspi_mm", &res_mem);
433d4363baaSMichael Kurz 	if (ret) {
434d4363baaSMichael Kurz 		debug("Error: can't get mmap base address(ret = %d)!\n", ret);
435d4363baaSMichael Kurz 		return -ENOMEM;
436d4363baaSMichael Kurz 	}
437d4363baaSMichael Kurz 
4382a6ca736SPatrice Chotard 	plat->max_hz = dev_read_u32_default(bus, "spi-max-frequency",
439d4363baaSMichael Kurz 					    STM32_QSPI_DEFAULT_SCK_FREQ);
440d4363baaSMichael Kurz 
441d4363baaSMichael Kurz 	plat->base = res_regs.start;
442d4363baaSMichael Kurz 	plat->memory_map = res_mem.start;
443d4363baaSMichael Kurz 
444d4363baaSMichael Kurz 	debug("%s: regs=<0x%x> mapped=<0x%x>, max-frequency=%d\n",
445d4363baaSMichael Kurz 	      __func__,
446d4363baaSMichael Kurz 	      plat->base,
447d4363baaSMichael Kurz 	      plat->memory_map,
448d4363baaSMichael Kurz 	      plat->max_hz
449d4363baaSMichael Kurz 	      );
450d4363baaSMichael Kurz 
451d4363baaSMichael Kurz 	return 0;
452d4363baaSMichael Kurz }
453d4363baaSMichael Kurz 
stm32_qspi_probe(struct udevice * bus)454d4363baaSMichael Kurz static int stm32_qspi_probe(struct udevice *bus)
455d4363baaSMichael Kurz {
456d4363baaSMichael Kurz 	struct stm32_qspi_platdata *plat = dev_get_platdata(bus);
457d4363baaSMichael Kurz 	struct stm32_qspi_priv *priv = dev_get_priv(bus);
458d4363baaSMichael Kurz 	struct dm_spi_bus *dm_spi_bus;
45912e7c91aSPatrice Chotard 	struct clk clk;
4605e46123bSPatrice Chotard 	struct reset_ctl reset_ctl;
46112e7c91aSPatrice Chotard 	int ret;
462d4363baaSMichael Kurz 
463d4363baaSMichael Kurz 	dm_spi_bus = bus->uclass_priv;
464d4363baaSMichael Kurz 
465d4363baaSMichael Kurz 	dm_spi_bus->max_hz = plat->max_hz;
466d4363baaSMichael Kurz 
467d4363baaSMichael Kurz 	priv->regs = (struct stm32_qspi_regs *)(uintptr_t)plat->base;
468d4363baaSMichael Kurz 
469d4363baaSMichael Kurz 	priv->max_hz = plat->max_hz;
470d4363baaSMichael Kurz 
471890bafd7SVikas Manocha 	ret = clk_get_by_index(bus, 0, &clk);
472890bafd7SVikas Manocha 	if (ret < 0)
473890bafd7SVikas Manocha 		return ret;
474890bafd7SVikas Manocha 
475890bafd7SVikas Manocha 	ret = clk_enable(&clk);
476890bafd7SVikas Manocha 
477890bafd7SVikas Manocha 	if (ret) {
478890bafd7SVikas Manocha 		dev_err(bus, "failed to enable clock\n");
479890bafd7SVikas Manocha 		return ret;
480890bafd7SVikas Manocha 	}
481541cd6e5SPatrice Chotard 
482541cd6e5SPatrice Chotard 	priv->clock_rate = clk_get_rate(&clk);
483541cd6e5SPatrice Chotard 	if (priv->clock_rate < 0) {
484541cd6e5SPatrice Chotard 		clk_disable(&clk);
485541cd6e5SPatrice Chotard 		return priv->clock_rate;
486541cd6e5SPatrice Chotard 	}
487541cd6e5SPatrice Chotard 
4885e46123bSPatrice Chotard 	ret = reset_get_by_index(bus, 0, &reset_ctl);
4895e46123bSPatrice Chotard 	if (ret) {
4905e46123bSPatrice Chotard 		if (ret != -ENOENT) {
4915e46123bSPatrice Chotard 			dev_err(bus, "failed to get reset\n");
4925e46123bSPatrice Chotard 			clk_disable(&clk);
4935e46123bSPatrice Chotard 			return ret;
4945e46123bSPatrice Chotard 		}
4955e46123bSPatrice Chotard 	} else {
4965e46123bSPatrice Chotard 		/* Reset QSPI controller */
4975e46123bSPatrice Chotard 		reset_assert(&reset_ctl);
4985e46123bSPatrice Chotard 		udelay(2);
4995e46123bSPatrice Chotard 		reset_deassert(&reset_ctl);
5005e46123bSPatrice Chotard 	}
501d4363baaSMichael Kurz 
502d4363baaSMichael Kurz 	setbits_le32(&priv->regs->cr, STM32_QSPI_CR_SSHIFT);
503d4363baaSMichael Kurz 
504d4363baaSMichael Kurz 	return 0;
505d4363baaSMichael Kurz }
506d4363baaSMichael Kurz 
stm32_qspi_remove(struct udevice * bus)507d4363baaSMichael Kurz static int stm32_qspi_remove(struct udevice *bus)
508d4363baaSMichael Kurz {
509d4363baaSMichael Kurz 	return 0;
510d4363baaSMichael Kurz }
511d4363baaSMichael Kurz 
stm32_qspi_claim_bus(struct udevice * dev)512d4363baaSMichael Kurz static int stm32_qspi_claim_bus(struct udevice *dev)
513d4363baaSMichael Kurz {
514d4363baaSMichael Kurz 	struct stm32_qspi_priv *priv;
515d4363baaSMichael Kurz 	struct udevice *bus;
516d4363baaSMichael Kurz 	struct spi_flash *flash;
517495f3b2aSChristophe Kerello 	struct dm_spi_slave_platdata *slave_plat;
518d4363baaSMichael Kurz 
519d4363baaSMichael Kurz 	bus = dev->parent;
520d4363baaSMichael Kurz 	priv = dev_get_priv(bus);
521d4363baaSMichael Kurz 	flash = dev_get_uclass_priv(dev);
522495f3b2aSChristophe Kerello 	slave_plat = dev_get_parent_platdata(dev);
523495f3b2aSChristophe Kerello 
524495f3b2aSChristophe Kerello 	if (slave_plat->cs >= STM32_MAX_NORCHIP)
525495f3b2aSChristophe Kerello 		return -ENODEV;
526495f3b2aSChristophe Kerello 
527495f3b2aSChristophe Kerello 	_stm32_qspi_set_cs(priv, slave_plat->cs);
528d4363baaSMichael Kurz 
529d4363baaSMichael Kurz 	_stm32_qspi_set_flash_size(priv, flash->size);
530d4363baaSMichael Kurz 
531d4363baaSMichael Kurz 	_stm32_qspi_enable(priv);
532d4363baaSMichael Kurz 
533d4363baaSMichael Kurz 	return 0;
534d4363baaSMichael Kurz }
535d4363baaSMichael Kurz 
stm32_qspi_release_bus(struct udevice * dev)536d4363baaSMichael Kurz static int stm32_qspi_release_bus(struct udevice *dev)
537d4363baaSMichael Kurz {
538d4363baaSMichael Kurz 	struct stm32_qspi_priv *priv;
539d4363baaSMichael Kurz 	struct udevice *bus;
540d4363baaSMichael Kurz 
541d4363baaSMichael Kurz 	bus = dev->parent;
542d4363baaSMichael Kurz 	priv = dev_get_priv(bus);
543d4363baaSMichael Kurz 
544d4363baaSMichael Kurz 	_stm32_qspi_disable(priv);
545d4363baaSMichael Kurz 
546d4363baaSMichael Kurz 	return 0;
547d4363baaSMichael Kurz }
548d4363baaSMichael Kurz 
stm32_qspi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)549d4363baaSMichael Kurz static int stm32_qspi_xfer(struct udevice *dev, unsigned int bitlen,
550d4363baaSMichael Kurz 			   const void *dout, void *din, unsigned long flags)
551d4363baaSMichael Kurz {
552d4363baaSMichael Kurz 	struct stm32_qspi_priv *priv;
553d4363baaSMichael Kurz 	struct udevice *bus;
554d4363baaSMichael Kurz 	struct spi_flash *flash;
555d4363baaSMichael Kurz 
556d4363baaSMichael Kurz 	bus = dev->parent;
557d4363baaSMichael Kurz 	priv = dev_get_priv(bus);
558d4363baaSMichael Kurz 	flash = dev_get_uclass_priv(dev);
559d4363baaSMichael Kurz 
560d4363baaSMichael Kurz 	return _stm32_qspi_xfer(priv, flash, bitlen, (const u8 *)dout,
561d4363baaSMichael Kurz 				(u8 *)din, flags);
562d4363baaSMichael Kurz }
563d4363baaSMichael Kurz 
stm32_qspi_set_speed(struct udevice * bus,uint speed)564d4363baaSMichael Kurz static int stm32_qspi_set_speed(struct udevice *bus, uint speed)
565d4363baaSMichael Kurz {
566d4363baaSMichael Kurz 	struct stm32_qspi_platdata *plat = bus->platdata;
567d4363baaSMichael Kurz 	struct stm32_qspi_priv *priv = dev_get_priv(bus);
568936abadaSPatrick Delaunay 	u32 qspi_clk = priv->clock_rate;
569936abadaSPatrick Delaunay 	u32 prescaler = 255;
570936abadaSPatrick Delaunay 	u32 csht;
571d4363baaSMichael Kurz 
572d4363baaSMichael Kurz 	if (speed > plat->max_hz)
573d4363baaSMichael Kurz 		speed = plat->max_hz;
574d4363baaSMichael Kurz 
575d4363baaSMichael Kurz 	if (speed > 0) {
576d4363baaSMichael Kurz 		prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1;
577d4363baaSMichael Kurz 		if (prescaler > 255)
578d4363baaSMichael Kurz 			prescaler = 255;
579d4363baaSMichael Kurz 		else if (prescaler < 0)
580d4363baaSMichael Kurz 			prescaler = 0;
581d4363baaSMichael Kurz 	}
582d4363baaSMichael Kurz 
583936abadaSPatrick Delaunay 	csht = DIV_ROUND_UP((5 * qspi_clk) / (prescaler + 1), 100000000);
584d4363baaSMichael Kurz 	csht = (csht - 1) & STM32_QSPI_DCR_CSHT_MASK;
585d4363baaSMichael Kurz 
586d4363baaSMichael Kurz 	_stm32_qspi_wait_for_not_busy(priv);
587d4363baaSMichael Kurz 
588d4363baaSMichael Kurz 	clrsetbits_le32(&priv->regs->cr,
589d4363baaSMichael Kurz 			STM32_QSPI_CR_PRESCALER_MASK <<
590d4363baaSMichael Kurz 			STM32_QSPI_CR_PRESCALER_SHIFT,
591d4363baaSMichael Kurz 			prescaler << STM32_QSPI_CR_PRESCALER_SHIFT);
592d4363baaSMichael Kurz 
593d4363baaSMichael Kurz 	clrsetbits_le32(&priv->regs->dcr,
594d4363baaSMichael Kurz 			STM32_QSPI_DCR_CSHT_MASK << STM32_QSPI_DCR_CSHT_SHIFT,
595d4363baaSMichael Kurz 			csht << STM32_QSPI_DCR_CSHT_SHIFT);
596d4363baaSMichael Kurz 
597d4363baaSMichael Kurz 	debug("%s: regs=%p, speed=%d\n", __func__, priv->regs,
598d4363baaSMichael Kurz 	      (qspi_clk / (prescaler + 1)));
599d4363baaSMichael Kurz 
600d4363baaSMichael Kurz 	return 0;
601d4363baaSMichael Kurz }
602d4363baaSMichael Kurz 
stm32_qspi_set_mode(struct udevice * bus,uint mode)603d4363baaSMichael Kurz static int stm32_qspi_set_mode(struct udevice *bus, uint mode)
604d4363baaSMichael Kurz {
605d4363baaSMichael Kurz 	struct stm32_qspi_priv *priv = dev_get_priv(bus);
606d4363baaSMichael Kurz 
607d4363baaSMichael Kurz 	_stm32_qspi_wait_for_not_busy(priv);
608d4363baaSMichael Kurz 
609d4363baaSMichael Kurz 	if ((mode & SPI_CPHA) && (mode & SPI_CPOL))
610d4363baaSMichael Kurz 		setbits_le32(&priv->regs->dcr, STM32_QSPI_DCR_CKMODE);
611d4363baaSMichael Kurz 	else if (!(mode & SPI_CPHA) && !(mode & SPI_CPOL))
612d4363baaSMichael Kurz 		clrbits_le32(&priv->regs->dcr, STM32_QSPI_DCR_CKMODE);
613d4363baaSMichael Kurz 	else
614d4363baaSMichael Kurz 		return -ENODEV;
615d4363baaSMichael Kurz 
616d4363baaSMichael Kurz 	if (mode & SPI_CS_HIGH)
617d4363baaSMichael Kurz 		return -ENODEV;
618d4363baaSMichael Kurz 
619d4363baaSMichael Kurz 	if (mode & SPI_RX_QUAD)
620d4363baaSMichael Kurz 		priv->mode |= SPI_RX_QUAD;
621d4363baaSMichael Kurz 	else if (mode & SPI_RX_DUAL)
622d4363baaSMichael Kurz 		priv->mode |= SPI_RX_DUAL;
623d4363baaSMichael Kurz 	else
624d4363baaSMichael Kurz 		priv->mode &= ~(SPI_RX_QUAD | SPI_RX_DUAL);
625d4363baaSMichael Kurz 
626d4363baaSMichael Kurz 	if (mode & SPI_TX_QUAD)
627d4363baaSMichael Kurz 		priv->mode |= SPI_TX_QUAD;
628d4363baaSMichael Kurz 	else if (mode & SPI_TX_DUAL)
629d4363baaSMichael Kurz 		priv->mode |= SPI_TX_DUAL;
630d4363baaSMichael Kurz 	else
631d4363baaSMichael Kurz 		priv->mode &= ~(SPI_TX_QUAD | SPI_TX_DUAL);
632d4363baaSMichael Kurz 
633d4363baaSMichael Kurz 	debug("%s: regs=%p, mode=%d rx: ", __func__, priv->regs, mode);
634d4363baaSMichael Kurz 
635d4363baaSMichael Kurz 	if (mode & SPI_RX_QUAD)
636d4363baaSMichael Kurz 		debug("quad, tx: ");
637d4363baaSMichael Kurz 	else if (mode & SPI_RX_DUAL)
638d4363baaSMichael Kurz 		debug("dual, tx: ");
639d4363baaSMichael Kurz 	else
640d4363baaSMichael Kurz 		debug("single, tx: ");
641d4363baaSMichael Kurz 
642d4363baaSMichael Kurz 	if (mode & SPI_TX_QUAD)
643d4363baaSMichael Kurz 		debug("quad\n");
644d4363baaSMichael Kurz 	else if (mode & SPI_TX_DUAL)
645d4363baaSMichael Kurz 		debug("dual\n");
646d4363baaSMichael Kurz 	else
647d4363baaSMichael Kurz 		debug("single\n");
648d4363baaSMichael Kurz 
649d4363baaSMichael Kurz 	return 0;
650d4363baaSMichael Kurz }
651d4363baaSMichael Kurz 
652d4363baaSMichael Kurz static const struct dm_spi_ops stm32_qspi_ops = {
653d4363baaSMichael Kurz 	.claim_bus	= stm32_qspi_claim_bus,
654d4363baaSMichael Kurz 	.release_bus	= stm32_qspi_release_bus,
655d4363baaSMichael Kurz 	.xfer		= stm32_qspi_xfer,
656d4363baaSMichael Kurz 	.set_speed	= stm32_qspi_set_speed,
657d4363baaSMichael Kurz 	.set_mode	= stm32_qspi_set_mode,
658d4363baaSMichael Kurz };
659d4363baaSMichael Kurz 
660d4363baaSMichael Kurz static const struct udevice_id stm32_qspi_ids[] = {
661d4363baaSMichael Kurz 	{ .compatible = "st,stm32-qspi" },
66276afe56aSChristophe Kerello 	{ .compatible = "st,stm32f469-qspi" },
663d4363baaSMichael Kurz 	{ }
664d4363baaSMichael Kurz };
665d4363baaSMichael Kurz 
666d4363baaSMichael Kurz U_BOOT_DRIVER(stm32_qspi) = {
667d4363baaSMichael Kurz 	.name	= "stm32_qspi",
668d4363baaSMichael Kurz 	.id	= UCLASS_SPI,
669d4363baaSMichael Kurz 	.of_match = stm32_qspi_ids,
670d4363baaSMichael Kurz 	.ops	= &stm32_qspi_ops,
671d4363baaSMichael Kurz 	.ofdata_to_platdata = stm32_qspi_ofdata_to_platdata,
672d4363baaSMichael Kurz 	.platdata_auto_alloc_size = sizeof(struct stm32_qspi_platdata),
673d4363baaSMichael Kurz 	.priv_auto_alloc_size = sizeof(struct stm32_qspi_priv),
674d4363baaSMichael Kurz 	.probe	= stm32_qspi_probe,
675d4363baaSMichael Kurz 	.remove = stm32_qspi_remove,
676d4363baaSMichael Kurz };
677