]>
Commit | Line | Data |
---|---|---|
d4363baa MK |
1 | /* |
2 | * (C) Copyright 2016 | |
3 | * | |
4 | * Michael Kurz, <michi.kurz@gmail.com> | |
5 | * | |
6 | * STM32 QSPI driver | |
7 | * | |
8 | * SPDX-License-Identifier: GPL-2.0+ | |
9 | */ | |
10 | ||
11 | #include <common.h> | |
12 | #include <malloc.h> | |
13 | #include <spi.h> | |
14 | #include <spi_flash.h> | |
15 | #include <asm/io.h> | |
16 | #include <dm.h> | |
17 | #include <errno.h> | |
18 | #include <asm/arch/stm32.h> | |
19 | #include <asm/arch/stm32_defs.h> | |
890bafd7 | 20 | #include <clk.h> |
d4363baa MK |
21 | |
22 | DECLARE_GLOBAL_DATA_PTR; | |
23 | ||
24 | struct stm32_qspi_regs { | |
25 | u32 cr; /* 0x00 */ | |
26 | u32 dcr; /* 0x04 */ | |
27 | u32 sr; /* 0x08 */ | |
28 | u32 fcr; /* 0x0C */ | |
29 | u32 dlr; /* 0x10 */ | |
30 | u32 ccr; /* 0x14 */ | |
31 | u32 ar; /* 0x18 */ | |
32 | u32 abr; /* 0x1C */ | |
33 | u32 dr; /* 0x20 */ | |
34 | u32 psmkr; /* 0x24 */ | |
35 | u32 psmar; /* 0x28 */ | |
36 | u32 pir; /* 0x2C */ | |
37 | u32 lptr; /* 0x30 */ | |
38 | }; | |
39 | ||
40 | /* | |
41 | * QUADSPI control register | |
42 | */ | |
43 | #define STM32_QSPI_CR_EN BIT(0) | |
44 | #define STM32_QSPI_CR_ABORT BIT(1) | |
45 | #define STM32_QSPI_CR_DMAEN BIT(2) | |
46 | #define STM32_QSPI_CR_TCEN BIT(3) | |
47 | #define STM32_QSPI_CR_SSHIFT BIT(4) | |
48 | #define STM32_QSPI_CR_DFM BIT(6) | |
49 | #define STM32_QSPI_CR_FSEL BIT(7) | |
50 | #define STM32_QSPI_CR_FTHRES_MASK GENMASK(4, 0) | |
51 | #define STM32_QSPI_CR_FTHRES_SHIFT (8) | |
52 | #define STM32_QSPI_CR_TEIE BIT(16) | |
53 | #define STM32_QSPI_CR_TCIE BIT(17) | |
54 | #define STM32_QSPI_CR_FTIE BIT(18) | |
55 | #define STM32_QSPI_CR_SMIE BIT(19) | |
56 | #define STM32_QSPI_CR_TOIE BIT(20) | |
57 | #define STM32_QSPI_CR_APMS BIT(22) | |
58 | #define STM32_QSPI_CR_PMM BIT(23) | |
59 | #define STM32_QSPI_CR_PRESCALER_MASK GENMASK(7, 0) | |
60 | #define STM32_QSPI_CR_PRESCALER_SHIFT (24) | |
61 | ||
62 | /* | |
63 | * QUADSPI device configuration register | |
64 | */ | |
65 | #define STM32_QSPI_DCR_CKMODE BIT(0) | |
66 | #define STM32_QSPI_DCR_CSHT_MASK GENMASK(2, 0) | |
67 | #define STM32_QSPI_DCR_CSHT_SHIFT (8) | |
68 | #define STM32_QSPI_DCR_FSIZE_MASK GENMASK(4, 0) | |
69 | #define STM32_QSPI_DCR_FSIZE_SHIFT (16) | |
70 | ||
71 | /* | |
72 | * QUADSPI status register | |
73 | */ | |
74 | #define STM32_QSPI_SR_TEF BIT(0) | |
75 | #define STM32_QSPI_SR_TCF BIT(1) | |
76 | #define STM32_QSPI_SR_FTF BIT(2) | |
77 | #define STM32_QSPI_SR_SMF BIT(3) | |
78 | #define STM32_QSPI_SR_TOF BIT(4) | |
79 | #define STM32_QSPI_SR_BUSY BIT(5) | |
80 | #define STM32_QSPI_SR_FLEVEL_MASK GENMASK(5, 0) | |
81 | #define STM32_QSPI_SR_FLEVEL_SHIFT (8) | |
82 | ||
83 | /* | |
84 | * QUADSPI flag clear register | |
85 | */ | |
86 | #define STM32_QSPI_FCR_CTEF BIT(0) | |
87 | #define STM32_QSPI_FCR_CTCF BIT(1) | |
88 | #define STM32_QSPI_FCR_CSMF BIT(3) | |
89 | #define STM32_QSPI_FCR_CTOF BIT(4) | |
90 | ||
91 | /* | |
92 | * QUADSPI communication configuration register | |
93 | */ | |
94 | #define STM32_QSPI_CCR_DDRM BIT(31) | |
95 | #define STM32_QSPI_CCR_DHHC BIT(30) | |
96 | #define STM32_QSPI_CCR_SIOO BIT(28) | |
97 | #define STM32_QSPI_CCR_FMODE_SHIFT (26) | |
98 | #define STM32_QSPI_CCR_DMODE_SHIFT (24) | |
99 | #define STM32_QSPI_CCR_DCYC_SHIFT (18) | |
100 | #define STM32_QSPI_CCR_DCYC_MASK GENMASK(4, 0) | |
101 | #define STM32_QSPI_CCR_ABSIZE_SHIFT (16) | |
102 | #define STM32_QSPI_CCR_ABMODE_SHIFT (14) | |
103 | #define STM32_QSPI_CCR_ADSIZE_SHIFT (12) | |
104 | #define STM32_QSPI_CCR_ADMODE_SHIFT (10) | |
105 | #define STM32_QSPI_CCR_IMODE_SHIFT (8) | |
106 | #define STM32_QSPI_CCR_INSTRUCTION_MASK GENMASK(7, 0) | |
107 | ||
108 | enum STM32_QSPI_CCR_IMODE { | |
109 | STM32_QSPI_CCR_IMODE_NONE = 0, | |
110 | STM32_QSPI_CCR_IMODE_ONE_LINE = 1, | |
111 | STM32_QSPI_CCR_IMODE_TWO_LINE = 2, | |
112 | STM32_QSPI_CCR_IMODE_FOUR_LINE = 3, | |
113 | }; | |
114 | ||
115 | enum STM32_QSPI_CCR_ADMODE { | |
116 | STM32_QSPI_CCR_ADMODE_NONE = 0, | |
117 | STM32_QSPI_CCR_ADMODE_ONE_LINE = 1, | |
118 | STM32_QSPI_CCR_ADMODE_TWO_LINE = 2, | |
119 | STM32_QSPI_CCR_ADMODE_FOUR_LINE = 3, | |
120 | }; | |
121 | ||
122 | enum STM32_QSPI_CCR_ADSIZE { | |
123 | STM32_QSPI_CCR_ADSIZE_8BIT = 0, | |
124 | STM32_QSPI_CCR_ADSIZE_16BIT = 1, | |
125 | STM32_QSPI_CCR_ADSIZE_24BIT = 2, | |
126 | STM32_QSPI_CCR_ADSIZE_32BIT = 3, | |
127 | }; | |
128 | ||
129 | enum STM32_QSPI_CCR_ABMODE { | |
130 | STM32_QSPI_CCR_ABMODE_NONE = 0, | |
131 | STM32_QSPI_CCR_ABMODE_ONE_LINE = 1, | |
132 | STM32_QSPI_CCR_ABMODE_TWO_LINE = 2, | |
133 | STM32_QSPI_CCR_ABMODE_FOUR_LINE = 3, | |
134 | }; | |
135 | ||
136 | enum STM32_QSPI_CCR_ABSIZE { | |
137 | STM32_QSPI_CCR_ABSIZE_8BIT = 0, | |
138 | STM32_QSPI_CCR_ABSIZE_16BIT = 1, | |
139 | STM32_QSPI_CCR_ABSIZE_24BIT = 2, | |
140 | STM32_QSPI_CCR_ABSIZE_32BIT = 3, | |
141 | }; | |
142 | ||
143 | enum STM32_QSPI_CCR_DMODE { | |
144 | STM32_QSPI_CCR_DMODE_NONE = 0, | |
145 | STM32_QSPI_CCR_DMODE_ONE_LINE = 1, | |
146 | STM32_QSPI_CCR_DMODE_TWO_LINE = 2, | |
147 | STM32_QSPI_CCR_DMODE_FOUR_LINE = 3, | |
148 | }; | |
149 | ||
150 | enum STM32_QSPI_CCR_FMODE { | |
151 | STM32_QSPI_CCR_IND_WRITE = 0, | |
152 | STM32_QSPI_CCR_IND_READ = 1, | |
153 | STM32_QSPI_CCR_AUTO_POLL = 2, | |
154 | STM32_QSPI_CCR_MEM_MAP = 3, | |
155 | }; | |
156 | ||
157 | /* default SCK frequency, unit: HZ */ | |
158 | #define STM32_QSPI_DEFAULT_SCK_FREQ 108000000 | |
159 | ||
160 | struct stm32_qspi_platdata { | |
161 | u32 base; | |
162 | u32 memory_map; | |
163 | u32 max_hz; | |
164 | }; | |
165 | ||
166 | struct stm32_qspi_priv { | |
167 | struct stm32_qspi_regs *regs; | |
541cd6e5 | 168 | ulong clock_rate; |
d4363baa MK |
169 | u32 max_hz; |
170 | u32 mode; | |
171 | ||
172 | u32 command; | |
173 | u32 address; | |
174 | u32 dummycycles; | |
175 | #define CMD_HAS_ADR BIT(24) | |
176 | #define CMD_HAS_DUMMY BIT(25) | |
177 | #define CMD_HAS_DATA BIT(26) | |
178 | }; | |
179 | ||
180 | static void _stm32_qspi_disable(struct stm32_qspi_priv *priv) | |
181 | { | |
182 | clrbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); | |
183 | } | |
184 | ||
185 | static void _stm32_qspi_enable(struct stm32_qspi_priv *priv) | |
186 | { | |
187 | setbits_le32(&priv->regs->cr, STM32_QSPI_CR_EN); | |
188 | } | |
189 | ||
190 | static void _stm32_qspi_wait_for_not_busy(struct stm32_qspi_priv *priv) | |
191 | { | |
192 | while (readl(&priv->regs->sr) & STM32_QSPI_SR_BUSY) | |
193 | ; | |
194 | } | |
195 | ||
196 | static void _stm32_qspi_wait_for_complete(struct stm32_qspi_priv *priv) | |
197 | { | |
198 | while (!(readl(&priv->regs->sr) & STM32_QSPI_SR_TCF)) | |
199 | ; | |
200 | } | |
201 | ||
202 | static void _stm32_qspi_wait_for_ftf(struct stm32_qspi_priv *priv) | |
203 | { | |
204 | while (!(readl(&priv->regs->sr) & STM32_QSPI_SR_FTF)) | |
205 | ; | |
206 | } | |
207 | ||
208 | static void _stm32_qspi_set_flash_size(struct stm32_qspi_priv *priv, u32 size) | |
209 | { | |
210 | u32 fsize = fls(size) - 1; | |
211 | clrsetbits_le32(&priv->regs->dcr, | |
212 | STM32_QSPI_DCR_FSIZE_MASK << STM32_QSPI_DCR_FSIZE_SHIFT, | |
213 | fsize << STM32_QSPI_DCR_FSIZE_SHIFT); | |
214 | } | |
215 | ||
216 | static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv) | |
217 | { | |
218 | unsigned int ccr_reg = 0; | |
219 | u8 imode, admode, dmode; | |
220 | u32 mode = priv->mode; | |
221 | u32 cmd = (priv->command & STM32_QSPI_CCR_INSTRUCTION_MASK); | |
222 | ||
223 | imode = STM32_QSPI_CCR_IMODE_ONE_LINE; | |
224 | admode = STM32_QSPI_CCR_ADMODE_ONE_LINE; | |
225 | ||
226 | if (mode & SPI_RX_QUAD) { | |
227 | dmode = STM32_QSPI_CCR_DMODE_FOUR_LINE; | |
228 | if (mode & SPI_TX_QUAD) { | |
229 | imode = STM32_QSPI_CCR_IMODE_FOUR_LINE; | |
230 | admode = STM32_QSPI_CCR_ADMODE_FOUR_LINE; | |
231 | } | |
232 | } else if (mode & SPI_RX_DUAL) { | |
233 | dmode = STM32_QSPI_CCR_DMODE_TWO_LINE; | |
234 | if (mode & SPI_TX_DUAL) { | |
235 | imode = STM32_QSPI_CCR_IMODE_TWO_LINE; | |
236 | admode = STM32_QSPI_CCR_ADMODE_TWO_LINE; | |
237 | } | |
238 | } else { | |
239 | dmode = STM32_QSPI_CCR_DMODE_ONE_LINE; | |
240 | } | |
241 | ||
242 | if (priv->command & CMD_HAS_DATA) | |
243 | ccr_reg |= (dmode << STM32_QSPI_CCR_DMODE_SHIFT); | |
244 | ||
245 | if (priv->command & CMD_HAS_DUMMY) | |
246 | ccr_reg |= ((priv->dummycycles & STM32_QSPI_CCR_DCYC_MASK) | |
247 | << STM32_QSPI_CCR_DCYC_SHIFT); | |
248 | ||
249 | if (priv->command & CMD_HAS_ADR) { | |
250 | ccr_reg |= (STM32_QSPI_CCR_ADSIZE_24BIT | |
251 | << STM32_QSPI_CCR_ADSIZE_SHIFT); | |
252 | ccr_reg |= (admode << STM32_QSPI_CCR_ADMODE_SHIFT); | |
253 | } | |
254 | ccr_reg |= (imode << STM32_QSPI_CCR_IMODE_SHIFT); | |
255 | ccr_reg |= cmd; | |
256 | return ccr_reg; | |
257 | } | |
258 | ||
259 | static void _stm32_qspi_enable_mmap(struct stm32_qspi_priv *priv, | |
260 | struct spi_flash *flash) | |
261 | { | |
262 | priv->command = flash->read_cmd | CMD_HAS_ADR | CMD_HAS_DATA | |
263 | | CMD_HAS_DUMMY; | |
264 | priv->dummycycles = flash->dummy_byte * 8; | |
265 | ||
266 | unsigned int ccr_reg = _stm32_qspi_gen_ccr(priv); | |
267 | ccr_reg |= (STM32_QSPI_CCR_MEM_MAP << STM32_QSPI_CCR_FMODE_SHIFT); | |
268 | ||
269 | _stm32_qspi_wait_for_not_busy(priv); | |
270 | ||
271 | writel(ccr_reg, &priv->regs->ccr); | |
272 | ||
273 | priv->dummycycles = 0; | |
274 | } | |
275 | ||
276 | static void _stm32_qspi_disable_mmap(struct stm32_qspi_priv *priv) | |
277 | { | |
278 | setbits_le32(&priv->regs->cr, STM32_QSPI_CR_ABORT); | |
279 | } | |
280 | ||
281 | static void _stm32_qspi_set_xfer_length(struct stm32_qspi_priv *priv, | |
282 | u32 length) | |
283 | { | |
284 | writel(length - 1, &priv->regs->dlr); | |
285 | } | |
286 | ||
287 | static void _stm32_qspi_start_xfer(struct stm32_qspi_priv *priv, u32 cr_reg) | |
288 | { | |
289 | writel(cr_reg, &priv->regs->ccr); | |
290 | ||
291 | if (priv->command & CMD_HAS_ADR) | |
292 | writel(priv->address, &priv->regs->ar); | |
293 | } | |
294 | ||
295 | static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, | |
296 | struct spi_flash *flash, unsigned int bitlen, | |
297 | const u8 *dout, u8 *din, unsigned long flags) | |
298 | { | |
299 | unsigned int words = bitlen / 8; | |
300 | ||
301 | if (flags & SPI_XFER_MMAP) { | |
302 | _stm32_qspi_enable_mmap(priv, flash); | |
303 | return 0; | |
304 | } else if (flags & SPI_XFER_MMAP_END) { | |
305 | _stm32_qspi_disable_mmap(priv); | |
306 | return 0; | |
307 | } | |
308 | ||
309 | if (bitlen == 0) | |
310 | return -1; | |
311 | ||
312 | if (bitlen % 8) { | |
313 | debug("spi_xfer: Non byte aligned SPI transfer\n"); | |
314 | return -1; | |
315 | } | |
316 | ||
317 | if (dout && din) { | |
318 | debug("spi_xfer: QSPI cannot have data in and data out set\n"); | |
319 | return -1; | |
320 | } | |
321 | ||
322 | if (!dout && (flags & SPI_XFER_BEGIN)) { | |
323 | debug("spi_xfer: QSPI transfer must begin with command\n"); | |
324 | return -1; | |
325 | } | |
326 | ||
327 | if (dout) { | |
328 | if (flags & SPI_XFER_BEGIN) { | |
329 | /* data is command */ | |
330 | priv->command = dout[0] | CMD_HAS_DATA; | |
331 | if (words >= 4) { | |
332 | /* address is here too */ | |
333 | priv->address = (dout[1] << 16) | | |
334 | (dout[2] << 8) | dout[3]; | |
335 | priv->command |= CMD_HAS_ADR; | |
336 | } | |
337 | ||
338 | if (words > 4) { | |
339 | /* rest is dummy bytes */ | |
340 | priv->dummycycles = (words - 4) * 8; | |
341 | priv->command |= CMD_HAS_DUMMY; | |
342 | } | |
343 | ||
344 | if (flags & SPI_XFER_END) { | |
345 | /* command without data */ | |
346 | priv->command &= ~(CMD_HAS_DATA); | |
347 | } | |
348 | } | |
349 | ||
350 | if (flags & SPI_XFER_END) { | |
351 | u32 ccr_reg = _stm32_qspi_gen_ccr(priv); | |
352 | ccr_reg |= STM32_QSPI_CCR_IND_WRITE | |
353 | << STM32_QSPI_CCR_FMODE_SHIFT; | |
354 | ||
355 | _stm32_qspi_wait_for_not_busy(priv); | |
356 | ||
357 | if (priv->command & CMD_HAS_DATA) | |
358 | _stm32_qspi_set_xfer_length(priv, words); | |
359 | ||
360 | _stm32_qspi_start_xfer(priv, ccr_reg); | |
361 | ||
362 | debug("%s: write: ccr:0x%08x adr:0x%08x\n", | |
363 | __func__, priv->regs->ccr, priv->regs->ar); | |
364 | ||
365 | if (priv->command & CMD_HAS_DATA) { | |
366 | _stm32_qspi_wait_for_ftf(priv); | |
367 | ||
368 | debug("%s: words:%d data:", __func__, words); | |
369 | ||
370 | int i = 0; | |
371 | while (words > i) { | |
372 | writeb(dout[i], &priv->regs->dr); | |
373 | debug("%02x ", dout[i]); | |
374 | i++; | |
375 | } | |
376 | debug("\n"); | |
377 | ||
378 | _stm32_qspi_wait_for_complete(priv); | |
379 | } else { | |
380 | _stm32_qspi_wait_for_not_busy(priv); | |
381 | } | |
382 | } | |
383 | } else if (din) { | |
384 | u32 ccr_reg = _stm32_qspi_gen_ccr(priv); | |
385 | ccr_reg |= STM32_QSPI_CCR_IND_READ | |
386 | << STM32_QSPI_CCR_FMODE_SHIFT; | |
387 | ||
388 | _stm32_qspi_wait_for_not_busy(priv); | |
389 | ||
390 | _stm32_qspi_set_xfer_length(priv, words); | |
391 | ||
392 | _stm32_qspi_start_xfer(priv, ccr_reg); | |
393 | ||
394 | debug("%s: read: ccr:0x%08x adr:0x%08x len:%d\n", __func__, | |
395 | priv->regs->ccr, priv->regs->ar, priv->regs->dlr); | |
396 | ||
397 | debug("%s: data:", __func__); | |
398 | ||
399 | int i = 0; | |
400 | while (words > i) { | |
401 | din[i] = readb(&priv->regs->dr); | |
402 | debug("%02x ", din[i]); | |
403 | i++; | |
404 | } | |
405 | debug("\n"); | |
406 | } | |
407 | ||
408 | return 0; | |
409 | } | |
410 | ||
411 | static int stm32_qspi_ofdata_to_platdata(struct udevice *bus) | |
412 | { | |
413 | struct fdt_resource res_regs, res_mem; | |
414 | struct stm32_qspi_platdata *plat = bus->platdata; | |
415 | const void *blob = gd->fdt_blob; | |
e160f7d4 | 416 | int node = dev_of_offset(bus); |
d4363baa MK |
417 | int ret; |
418 | ||
419 | ret = fdt_get_named_resource(blob, node, "reg", "reg-names", | |
420 | "QuadSPI", &res_regs); | |
421 | if (ret) { | |
422 | debug("Error: can't get regs base addresses(ret = %d)!\n", ret); | |
423 | return -ENOMEM; | |
424 | } | |
425 | ret = fdt_get_named_resource(blob, node, "reg", "reg-names", | |
426 | "QuadSPI-memory", &res_mem); | |
427 | if (ret) { | |
428 | debug("Error: can't get mmap base address(ret = %d)!\n", ret); | |
429 | return -ENOMEM; | |
430 | } | |
431 | ||
432 | plat->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", | |
433 | STM32_QSPI_DEFAULT_SCK_FREQ); | |
434 | ||
435 | plat->base = res_regs.start; | |
436 | plat->memory_map = res_mem.start; | |
437 | ||
438 | debug("%s: regs=<0x%x> mapped=<0x%x>, max-frequency=%d\n", | |
439 | __func__, | |
440 | plat->base, | |
441 | plat->memory_map, | |
442 | plat->max_hz | |
443 | ); | |
444 | ||
445 | return 0; | |
446 | } | |
447 | ||
448 | static int stm32_qspi_probe(struct udevice *bus) | |
449 | { | |
450 | struct stm32_qspi_platdata *plat = dev_get_platdata(bus); | |
451 | struct stm32_qspi_priv *priv = dev_get_priv(bus); | |
452 | struct dm_spi_bus *dm_spi_bus; | |
453 | ||
454 | dm_spi_bus = bus->uclass_priv; | |
455 | ||
456 | dm_spi_bus->max_hz = plat->max_hz; | |
457 | ||
458 | priv->regs = (struct stm32_qspi_regs *)(uintptr_t)plat->base; | |
459 | ||
460 | priv->max_hz = plat->max_hz; | |
461 | ||
890bafd7 VM |
462 | #ifdef CONFIG_CLK |
463 | int ret; | |
464 | struct clk clk; | |
465 | ret = clk_get_by_index(bus, 0, &clk); | |
466 | if (ret < 0) | |
467 | return ret; | |
468 | ||
469 | ret = clk_enable(&clk); | |
470 | ||
471 | if (ret) { | |
472 | dev_err(bus, "failed to enable clock\n"); | |
473 | return ret; | |
474 | } | |
541cd6e5 PC |
475 | |
476 | priv->clock_rate = clk_get_rate(&clk); | |
477 | if (priv->clock_rate < 0) { | |
478 | clk_disable(&clk); | |
479 | return priv->clock_rate; | |
480 | } | |
481 | ||
890bafd7 | 482 | #endif |
d4363baa MK |
483 | |
484 | setbits_le32(&priv->regs->cr, STM32_QSPI_CR_SSHIFT); | |
485 | ||
486 | return 0; | |
487 | } | |
488 | ||
489 | static int stm32_qspi_remove(struct udevice *bus) | |
490 | { | |
491 | return 0; | |
492 | } | |
493 | ||
494 | static int stm32_qspi_claim_bus(struct udevice *dev) | |
495 | { | |
496 | struct stm32_qspi_priv *priv; | |
497 | struct udevice *bus; | |
498 | struct spi_flash *flash; | |
499 | ||
500 | bus = dev->parent; | |
501 | priv = dev_get_priv(bus); | |
502 | flash = dev_get_uclass_priv(dev); | |
503 | ||
504 | _stm32_qspi_set_flash_size(priv, flash->size); | |
505 | ||
506 | _stm32_qspi_enable(priv); | |
507 | ||
508 | return 0; | |
509 | } | |
510 | ||
511 | static int stm32_qspi_release_bus(struct udevice *dev) | |
512 | { | |
513 | struct stm32_qspi_priv *priv; | |
514 | struct udevice *bus; | |
515 | ||
516 | bus = dev->parent; | |
517 | priv = dev_get_priv(bus); | |
518 | ||
519 | _stm32_qspi_disable(priv); | |
520 | ||
521 | return 0; | |
522 | } | |
523 | ||
524 | static int stm32_qspi_xfer(struct udevice *dev, unsigned int bitlen, | |
525 | const void *dout, void *din, unsigned long flags) | |
526 | { | |
527 | struct stm32_qspi_priv *priv; | |
528 | struct udevice *bus; | |
529 | struct spi_flash *flash; | |
530 | ||
531 | bus = dev->parent; | |
532 | priv = dev_get_priv(bus); | |
533 | flash = dev_get_uclass_priv(dev); | |
534 | ||
535 | return _stm32_qspi_xfer(priv, flash, bitlen, (const u8 *)dout, | |
536 | (u8 *)din, flags); | |
537 | } | |
538 | ||
539 | static int stm32_qspi_set_speed(struct udevice *bus, uint speed) | |
540 | { | |
541 | struct stm32_qspi_platdata *plat = bus->platdata; | |
542 | struct stm32_qspi_priv *priv = dev_get_priv(bus); | |
543 | ||
544 | if (speed > plat->max_hz) | |
545 | speed = plat->max_hz; | |
546 | ||
541cd6e5 | 547 | u32 qspi_clk = priv->clock_rate; |
d4363baa MK |
548 | u32 prescaler = 255; |
549 | if (speed > 0) { | |
550 | prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1; | |
551 | if (prescaler > 255) | |
552 | prescaler = 255; | |
553 | else if (prescaler < 0) | |
554 | prescaler = 0; | |
555 | } | |
556 | ||
557 | u32 csht = DIV_ROUND_UP((5 * qspi_clk) / (prescaler + 1), 100000000); | |
558 | csht = (csht - 1) & STM32_QSPI_DCR_CSHT_MASK; | |
559 | ||
560 | _stm32_qspi_wait_for_not_busy(priv); | |
561 | ||
562 | clrsetbits_le32(&priv->regs->cr, | |
563 | STM32_QSPI_CR_PRESCALER_MASK << | |
564 | STM32_QSPI_CR_PRESCALER_SHIFT, | |
565 | prescaler << STM32_QSPI_CR_PRESCALER_SHIFT); | |
566 | ||
567 | ||
568 | clrsetbits_le32(&priv->regs->dcr, | |
569 | STM32_QSPI_DCR_CSHT_MASK << STM32_QSPI_DCR_CSHT_SHIFT, | |
570 | csht << STM32_QSPI_DCR_CSHT_SHIFT); | |
571 | ||
572 | debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, | |
573 | (qspi_clk / (prescaler + 1))); | |
574 | ||
575 | return 0; | |
576 | } | |
577 | ||
578 | static int stm32_qspi_set_mode(struct udevice *bus, uint mode) | |
579 | { | |
580 | struct stm32_qspi_priv *priv = dev_get_priv(bus); | |
581 | ||
582 | _stm32_qspi_wait_for_not_busy(priv); | |
583 | ||
584 | if ((mode & SPI_CPHA) && (mode & SPI_CPOL)) | |
585 | setbits_le32(&priv->regs->dcr, STM32_QSPI_DCR_CKMODE); | |
586 | else if (!(mode & SPI_CPHA) && !(mode & SPI_CPOL)) | |
587 | clrbits_le32(&priv->regs->dcr, STM32_QSPI_DCR_CKMODE); | |
588 | else | |
589 | return -ENODEV; | |
590 | ||
591 | if (mode & SPI_CS_HIGH) | |
592 | return -ENODEV; | |
593 | ||
594 | if (mode & SPI_RX_QUAD) | |
595 | priv->mode |= SPI_RX_QUAD; | |
596 | else if (mode & SPI_RX_DUAL) | |
597 | priv->mode |= SPI_RX_DUAL; | |
598 | else | |
599 | priv->mode &= ~(SPI_RX_QUAD | SPI_RX_DUAL); | |
600 | ||
601 | if (mode & SPI_TX_QUAD) | |
602 | priv->mode |= SPI_TX_QUAD; | |
603 | else if (mode & SPI_TX_DUAL) | |
604 | priv->mode |= SPI_TX_DUAL; | |
605 | else | |
606 | priv->mode &= ~(SPI_TX_QUAD | SPI_TX_DUAL); | |
607 | ||
608 | debug("%s: regs=%p, mode=%d rx: ", __func__, priv->regs, mode); | |
609 | ||
610 | if (mode & SPI_RX_QUAD) | |
611 | debug("quad, tx: "); | |
612 | else if (mode & SPI_RX_DUAL) | |
613 | debug("dual, tx: "); | |
614 | else | |
615 | debug("single, tx: "); | |
616 | ||
617 | if (mode & SPI_TX_QUAD) | |
618 | debug("quad\n"); | |
619 | else if (mode & SPI_TX_DUAL) | |
620 | debug("dual\n"); | |
621 | else | |
622 | debug("single\n"); | |
623 | ||
624 | return 0; | |
625 | } | |
626 | ||
627 | static const struct dm_spi_ops stm32_qspi_ops = { | |
628 | .claim_bus = stm32_qspi_claim_bus, | |
629 | .release_bus = stm32_qspi_release_bus, | |
630 | .xfer = stm32_qspi_xfer, | |
631 | .set_speed = stm32_qspi_set_speed, | |
632 | .set_mode = stm32_qspi_set_mode, | |
633 | }; | |
634 | ||
635 | static const struct udevice_id stm32_qspi_ids[] = { | |
636 | { .compatible = "st,stm32-qspi" }, | |
637 | { } | |
638 | }; | |
639 | ||
640 | U_BOOT_DRIVER(stm32_qspi) = { | |
641 | .name = "stm32_qspi", | |
642 | .id = UCLASS_SPI, | |
643 | .of_match = stm32_qspi_ids, | |
644 | .ops = &stm32_qspi_ops, | |
645 | .ofdata_to_platdata = stm32_qspi_ofdata_to_platdata, | |
646 | .platdata_auto_alloc_size = sizeof(struct stm32_qspi_platdata), | |
647 | .priv_auto_alloc_size = sizeof(struct stm32_qspi_priv), | |
648 | .probe = stm32_qspi_probe, | |
649 | .remove = stm32_qspi_remove, | |
650 | }; |