ChibiOS 21.11.5
hal_xsnor_macronix_mx25_impl.inc
Go to the documentation of this file.
1/*
2 ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/**
18 * @file hal_xsnor_macronix_mx25_impl.inc
19 * @brief Template of SNOR Macronix MX25 source.
20 * @note This is a template file, can be edited directly.
21 *
22 * @addtogroup HAL_XSNOR_MACRONIX_MX25
23 * @{
24 */
25
26/* This is an, automatically generated, implementation file that can be
27 manually edited, it is not re-generated if already present.*/
28
29#include <string.h>
30
31#define PAGE_SIZE 256U
32#define PAGE_MASK (PAGE_SIZE - 1U)
33/**
34 * @name Command codes, SPI mode
35 * @{
36 */
37#define CMD_SPI_READ3B 0x03U
38#define CMD_SPI_FAST_READ3B 0x0BU
39#define CMD_SPI_PP3B 0x02U
40#define CMD_SPI_SE3B 0x20U
41#define CMD_SPI_BE3B 0xD8U
42#define CMD_SPI_CE 0xC7U
43#define CMD_SPI_READ4B 0x13U
44#define CMD_SPI_FAST_READ4B 0x0CU
45#define CMD_SPI_PP4B 0x12U
46#define CMD_SPI_SE4B 0x21U
47#define CMD_SPI_BE4B 0xDCU
48#define CMD_SPI_WREN 0x06U
49#define CMD_SPI_WRDI 0x04U
50#define CMD_SPI_PE_SUSPEND 0xB0U
51#define CMD_SPI_PE_RESUME 0x30U
52#define CMD_SPI_DP 0xB9U
53#define CMD_SPI_SBL 0xC0U
54#define CMD_SPI_ENSO 0xB1U
55#define CMD_SPI_EXSO 0xC1U
56#define CMD_SPI_NOP 0x00U
57#define CMD_SPI_RSTEN 0x66U
58#define CMD_SPI_RST 0x99U
59#define CMD_SPI_RDID 0x9FU
60#define CMD_SPI_RDSFDP 0x5AU
61#define CMD_SPI_RDSR 0x05U
62#define CMD_SPI_RDCR 0x15U
63#define CMD_SPI_WRSR 0x01U
64#define CMD_SPI_RDCR2 0x71U
65#define CMD_SPI_WRCR2 0x72U
66#define CMD_SPI_RDFBR 0x16U
67#define CMD_SPI_WRFBR 0x17U
68#define CMD_SPI_ESFBR 0x18U
69#define CMD_SPI_RDSCUR 0x2BU
70#define CMD_SPI_WRSCUR 0x2FU
71#define CMD_SPI_WRLR 0x2CU
72#define CMD_SPI_RDLR 0x2DU
73#define CMD_SPI_WRSPB 0xE3U
74#define CMD_SPI_ESSPB 0xE4U
75#define CMD_SPI_RDSPB 0xE2U
76#define CMD_SPI_WRDPB 0xE1U
77#define CMD_SPI_RDDPB 0xE0U
78#define CMD_SPI_WPSEL 0x68U
79#define CMD_SPI_GBLK 0x7EU
80#define CMD_SPI_GBULK 0x98U
81#define CMD_SPI_RDPASS 0x27U
82#define CMD_SPI_WRPASS 0x28U
83#define CMD_SPI_PASSULK 0x29U
84/** @} */
85
86/**
87 * @name Command codes, OPI mode
88 * @{
89 */
90#define CMD_OPI_8READ 0xEC13U
91#define CMD_OPI_8DTRD 0xEE11U
92#define CMD_OPI_RDID 0x9F60U
93#define CMD_OPI_RDSFDP 0x5AA5U
94#define CMD_OPI_PP 0x12EDU
95#define CMD_OPI_SE 0x21DEU
96#define CMD_OPI_BE 0xDC23U
97#define CMD_OPI_CE 0xC738U
98#define CMD_OPI_WREN 0x06F9U
99#define CMD_OPI_WRDI 0x04FBU
100#define CMD_OPI_PE_SUSPEND 0xB04FU
101#define CMD_OPI_PE_RESUME 0x30CFU
102#define CMD_OPI_DP 0xB946U
103#define CMD_OPI_SBL 0xC03FU
104#define CMD_OPI_ENSO 0xB14EU
105#define CMD_OPI_EXSO 0xC13EU
106#define CMD_OPI_NOP 0x00FFU
107#define CMD_OPI_RSTEN 0x6699U
108#define CMD_OPI_RST 0x9966U
109#define CMD_OPI_RDSR 0x05FAU
110#define CMD_OPI_RDCR 0x15EAU
111#define CMD_OPI_WRSR 0x01FEU
112#define CMD_OPI_WRCR 0x01FEU
113#define CMD_OPI_RDCR2 0x718EU
114#define CMD_OPI_WRCR2 0x728DU
115#define CMD_OPI_RDFBR 0x16E9U
116#define CMD_OPI_WRFBR 0x17E8U
117#define CMD_OPI_ESFBR 0x18E7U
118#define CMD_OPI_RDSCUR 0x2BD4U
119#define CMD_OPI_WRSCUR 0x2FD0U
120#define CMD_OPI_WRLR 0x2CD3U
121#define CMD_OPI_RDLR 0x2DD2U
122#define CMD_OPI_WRSPB 0xE31CU
123#define CMD_OPI_ESSPB 0xE41BU
124#define CMD_OPI_RDSPB 0xE21DU
125#define CMD_OPI_WRDPB 0xE11EU
126#define CMD_OPI_RDDPB 0xE01FU
127#define CMD_OPI_WPSEL 0x6897U
128#define CMD_OPI_GBLK 0x7E81U
129#define CMD_OPI_GBULK 0x9867U
130#define CMD_OPI_RDPASS 0x27D8U
131#define CMD_OPI_WRPASS 0x28D7U
132#define CMD_OPI_PASSULK 0x29D6U
133/** @} */
134
135/**
136 * @name Flags status register bits
137 * @{
138 */
139#define FLAGS_WPSEL 0x80U
140#define FLAGS_E_FAIL 0x40U
141#define FLAGS_P_FAIL 0x20U
142#define FLAGS_ESB 0x08U
143#define FLAGS_PSB 0x04U
144#define FLAGS_LDSO 0x02U
145#define FLAGS_SECURED_OTP 0x01U
146#define FLAGS_ALL_ERRORS (FLAGS_E_FAIL | FLAGS_P_FAIL)
147/** @} */
148
149/**
150 * @name MX25-required transfer modes
151 * @{
152 */
153#define CFG_C8_SPI (WSPI_CFG_CMD_SIZE_8 | \
154 WSPI_CFG_CMD_MODE_ONE_LINE | \
155 WSPI_CFG_ADDR_MODE_NONE | \
156 WSPI_CFG_ALT_MODE_NONE | \
157 WSPI_CFG_DATA_MODE_NONE)
158
159#define CFG_C16_8STR (WSPI_CFG_CMD_SIZE_16 | \
160 WSPI_CFG_CMD_MODE_EIGHT_LINES | \
161 WSPI_CFG_ADDR_MODE_NONE | \
162 WSPI_CFG_ALT_MODE_NONE | \
163 WSPI_CFG_DATA_MODE_NONE)
164
165#define CFG_C16_8DTR (WSPI_CFG_CMD_SIZE_16 | \
166 WSPI_CFG_CMD_MODE_EIGHT_LINES | \
167 WSPI_CFG_ADDR_MODE_NONE | \
168 WSPI_CFG_ALT_MODE_NONE | \
169 WSPI_CFG_DATA_MODE_NONE | \
170 WSPI_CFG_ALL_DTR)
171
172#define CFG_C8_A32_SPI (WSPI_CFG_CMD_SIZE_8 | \
173 WSPI_CFG_CMD_MODE_ONE_LINE | \
174 WSPI_CFG_ADDR_MODE_ONE_LINE | \
175 WSPI_CFG_ADDR_SIZE_32 | \
176 WSPI_CFG_ALT_MODE_NONE | \
177 WSPI_CFG_DATA_MODE_NONE)
178
179#define CFG_C16_A32_8STR (WSPI_CFG_CMD_SIZE_16 | \
180 WSPI_CFG_CMD_MODE_EIGHT_LINES | \
181 WSPI_CFG_ADDR_MODE_EIGHT_LINES | \
182 WSPI_CFG_ADDR_SIZE_32 | \
183 WSPI_CFG_ALT_MODE_NONE | \
184 WSPI_CFG_DATA_MODE_NONE)
185
186#define CFG_C16_A32_8DTR (WSPI_CFG_CMD_SIZE_16 | \
187 WSPI_CFG_CMD_MODE_EIGHT_LINES | \
188 WSPI_CFG_ADDR_MODE_EIGHT_LINES | \
189 WSPI_CFG_ADDR_SIZE_32 | \
190 WSPI_CFG_ALT_MODE_NONE | \
191 WSPI_CFG_DATA_MODE_NONE | \
192 WSPI_CFG_ALL_DTR)
193
194#define CFG_C8_DATA_SPI (WSPI_CFG_CMD_SIZE_8 | \
195 WSPI_CFG_CMD_MODE_ONE_LINE | \
196 WSPI_CFG_ADDR_MODE_NONE | \
197 WSPI_CFG_ALT_MODE_NONE | \
198 WSPI_CFG_DATA_MODE_ONE_LINE)
199
200#define CFG_C16_DATA_8STR (WSPI_CFG_CMD_SIZE_16 | \
201 WSPI_CFG_CMD_MODE_EIGHT_LINES | \
202 WSPI_CFG_ADDR_MODE_NONE | \
203 WSPI_CFG_ALT_MODE_NONE | \
204 WSPI_CFG_DATA_MODE_EIGHT_LINES)
205
206#define CFG_C16_DATA_8DTR (WSPI_CFG_CMD_SIZE_16 | \
207 WSPI_CFG_CMD_MODE_EIGHT_LINES | \
208 WSPI_CFG_ADDR_MODE_NONE | \
209 WSPI_CFG_ALT_MODE_NONE | \
210 WSPI_CFG_DATA_MODE_EIGHT_LINES | \
211 WSPI_CFG_ALL_DTR | \
212 WSPI_CFG_DQS_ENABLE)
213
214#define CFG_C8_A32_DATA_SPI (WSPI_CFG_CMD_SIZE_8 | \
215 WSPI_CFG_CMD_MODE_ONE_LINE | \
216 WSPI_CFG_ADDR_MODE_ONE_LINE | \
217 WSPI_CFG_ADDR_SIZE_32 | \
218 WSPI_CFG_ALT_MODE_NONE | \
219 WSPI_CFG_DATA_MODE_ONE_LINE)
220
221#define CFG_C16_A32_DATA_8STR (WSPI_CFG_CMD_SIZE_16 | \
222 WSPI_CFG_CMD_MODE_EIGHT_LINES | \
223 WSPI_CFG_ADDR_MODE_EIGHT_LINES | \
224 WSPI_CFG_ADDR_SIZE_32 | \
225 WSPI_CFG_ALT_MODE_NONE | \
226 WSPI_CFG_DATA_MODE_EIGHT_LINES)
227
228#define CFG_C16_A32_DATA_8DTR (WSPI_CFG_CMD_SIZE_16 | \
229 WSPI_CFG_CMD_MODE_EIGHT_LINES | \
230 WSPI_CFG_ADDR_MODE_EIGHT_LINES | \
231 WSPI_CFG_ADDR_SIZE_32 | \
232 WSPI_CFG_ALT_MODE_NONE | \
233 WSPI_CFG_DATA_MODE_EIGHT_LINES | \
234 WSPI_CFG_ALL_DTR | \
235 WSPI_CFG_DQS_ENABLE)
236/** @} */
237
238#if (XSNOR_USE_WSPI == TRUE) || defined(__DOXYGEN__)
239static const xsnor_commands_t cmd_spi = {
240 .cmd = CFG_C8_SPI,
241 .cmd_addr = CFG_C8_A32_SPI,
242 .cmd_data = CFG_C8_DATA_SPI,
243 .cmd_addr_data = CFG_C8_A32_DATA_SPI
244};
245
247 .cmd = CFG_C16_8STR,
248 .cmd_addr = CFG_C16_A32_8STR,
249 .cmd_data = CFG_C16_DATA_8STR,
250 .cmd_addr_data = CFG_C16_A32_DATA_8STR
251};
252
254 .cmd = CFG_C16_8DTR,
255 .cmd_addr = CFG_C16_A32_8DTR,
256 .cmd_data = CFG_C16_DATA_8DTR,
257 .cmd_addr_data = CFG_C16_A32_DATA_8DTR
258};
259
260/* 1x MX25_CMD_SPI_RSTEN command.*/
262 .cmd = CMD_SPI_RSTEN,
263 .cfg = CFG_C8_SPI,
264 .addr = 0,
265 .alt = 0,
266 .dummy = 0
267};
268
269/* 1x MX25_CMD_SPI_RST command.*/
271 .cmd = CMD_SPI_RST,
272 .cfg = CFG_C8_SPI,
273 .addr = 0,
274 .alt = 0,
275 .dummy = 0
276};
277
278/* 8xSTR MX25_CMD_OPI_RSTEN command.*/
280 .cmd = CMD_OPI_RSTEN,
281 .cfg = CFG_C16_8STR,
282 .addr = 0,
283 .alt = 0,
284 .dummy = 0
285};
286
287/* 8xSTR MX25_CMD_OPI_RST command.*/
289 .cmd = CMD_OPI_RST,
290 .cfg = CFG_C16_8STR,
291 .addr = 0,
292 .alt = 0,
293 .dummy = 0
294};
295
296/* 8xDTR MX25_CMD_OPI_RSTEN command.*/
298 .cmd = CMD_OPI_RSTEN,
299 .cfg = CFG_C16_8DTR,
300 .addr = 0,
301 .alt = 0,
302 .dummy = 0
303};
304
305/* 8xDTR MX25_CMD_OPI_RST command.*/
307 .cmd = CMD_OPI_RST,
308 .cfg = CFG_C16_8DTR,
309 .addr = 0,
310 .alt = 0,
311 .dummy = 0
312};
313#endif /* XSNOR_USE_WSPI == TRUE */
314
315/* Device identifiers.*/
316static const uint8_t mx25_manufacturer_ids[] = {0xC2};
317static const uint8_t mx25_memory_type_ids[] = {0x85};
318
319/*===========================================================================*/
320/* Module local functions. */
321/*===========================================================================*/
322
323static bool mx25_find_id(const uint8_t *set, size_t size, uint8_t element) {
324 size_t i;
325
326 for (i = 0; i < size; i++) {
327 if (set[i] == element) {
328 return true;
329 }
330 }
331 return false;
332}
333
335
336 do {
337 if ((self->config->options & MX25_OPT_NICE_WAITING) != 0U) {
339 }
340
341 /* Read status command.*/
342 if (self->config->bus_type == XSNOR_BUS_MODE_SPI) {
344 1U, &self->config->buffers->databuf[0]);
345 }
346 else {
348 0U, 4U, 2U,
349 &self->config->buffers->databuf[0]);
350 }
351 } while ((self->config->buffers->databuf[0] & 1U) != 0U);
352
353 /* Reading security register and checking for errors.*/
354 if (self->config->bus_type == XSNOR_BUS_MODE_SPI) {
356 1U, &self->config->buffers->databuf[0]);
357 }
358 else {
360 0U, 4U, 2U, /* Note: always 4 dummies.*/
361 &self->config->buffers->databuf[0]);
362 }
363
364 if ((self->config->buffers->databuf[0] & FLAGS_ALL_ERRORS) != 0U) {
365
366 return FLASH_ERROR_PROGRAM;
367 }
368
369 return FLASH_NO_ERROR;
370}
371
372static inline bool mx25_spi_4bytes(const hal_xsnor_macronix_mx25_c *self) {
373
374 return (self->descriptor.attributes & FLASH_ATTR_SPI_4BYTES_ADDR_HINT) != 0U;
375}
376
377#if (XSNOR_USE_WSPI == TRUE) || defined(__DOXYGEN__)
379
380 /* If the device is in one bit mode then the following commands are
381 rejected because shorter than 8 bits. If the device is in multiple
382 bits mode then the commands are accepted and the device is reset to
383 one bit mode.*/
384 if ((self->config->options &MX25_OPT_USE_DTR) != 0U) {
385 wspiCommand(self->config->bus.wspi.drv, &cmd_reset_enable_8dtr);
386 wspiCommand(self->config->bus.wspi.drv, &cmd_reset_memory_8dtr);
387 }
388 else {
389 wspiCommand(self->config->bus.wspi.drv, &cmd_reset_enable_8str);
390 wspiCommand(self->config->bus.wspi.drv, &cmd_reset_memory_8str);
391 }
392
393 /* Now the device should be in one bit mode for sure and we perform a
394 device reset.*/
395 wspiCommand(self->config->bus.wspi.drv, &cmd_reset_enable_spi);
396 wspiCommand(self->config->bus.wspi.drv, &cmd_reset_memory_spi);
397
398 /* The device requires at least 10uS to recover after a reset, it could
399 need up to 100mS in case a reset occurred during a chip erase, 50uS
400 covers most cases.*/
402}
403
404static void mx25_read_id(hal_xsnor_macronix_mx25_c *self, uint8_t *buf) {
405 wspi_command_t cmd;
406
407 if ((self->config->options & MX25_OPT_NO_WIDTH_SWITCH) != 0U) {
408 /* Not switching, assuming it is already in final bus mode.*/
409 switch (self->config->bus_type) {
411 cmd.cfg = CFG_C8_DATA_SPI;
412 cmd.cmd = CMD_SPI_RDID;
413 break;
415 if ((self->config->options & MX25_OPT_USE_DTR) != 0U) {
417 }
418 else {
420 }
421 cmd.cmd = CMD_OPI_RDID;
422 break;
423 default:
424 osalDbgAssert(false, "invalid bus type");
425 buf[0] = 0;
426 buf[1] = 0;
427 buf[2] = 0;
428 return;
429 }
430 }
431 else {
432 /* It is post-reset, before going to switch, assuming SPI.*/
433 cmd.cfg = CFG_C8_DATA_SPI;
434 cmd.cmd = CMD_SPI_RDID;
435 }
436 cmd.addr = 0U;
437 cmd.alt = 0U;
438 cmd.dummy = 0U;
439 wspiReceive(self->config->bus.wspi.drv, &cmd, 3U, buf);
440}
441
443 uint32_t addr, const uint8_t *value) {
444 wspi_command_t cmd;
445
446 if ((self->config->options & MX25_OPT_NO_WIDTH_SWITCH) != 0U) {
447 /* Not switching, assuming it is already in final bus mode.*/
448 switch (self->config->bus_type) {
450 cmd.cfg = CFG_C8_SPI;
451 cmd.cmd = CMD_SPI_WREN;
452 break;
454 if ((self->config->options & MX25_OPT_USE_DTR) != 0U) {
455 cmd.cfg = CFG_C16_8DTR;
456 }
457 else {
458 cmd.cfg = CFG_C16_8STR;
459 }
460 cmd.cmd = CMD_OPI_WREN;
461 break;
462 default:
463 osalDbgAssert(false, "invalid bus type");
464 return;
465 }
466 }
467 else {
468 /* It is post-reset, before going to switch, assuming SPI.*/
469 cmd.cfg = CFG_C8_SPI;
470 cmd.cmd = CMD_SPI_WREN;
471 }
472 cmd.addr = 0U;
473 cmd.alt = 0U;
474 cmd.dummy = 0U;
475 wspiCommand(self->config->bus.wspi.drv, &cmd);
476
477 if ((self->config->options & MX25_OPT_NO_WIDTH_SWITCH) != 0U) {
478 /* Not switching, assuming it is already in final bus mode.*/
479 switch (self->config->bus_type) {
482 cmd.cmd = CMD_SPI_WRCR2;
483 break;
485 if ((self->config->options & MX25_OPT_USE_DTR) != 0U) {
487 }
488 else {
490 }
491 cmd.cmd = CMD_OPI_WRCR2;
492 break;
493 default:
494 osalDbgAssert(false, "invalid bus type");
495 return;
496 }
497 }
498 else {
499 /* It is post-reset, before going to switch, assuming SPI.*/
501 cmd.cmd = CMD_SPI_WRCR2;
502 }
503 cmd.addr = addr;
504 cmd.alt = 0U;
505 cmd.dummy = 0U;
506 wspiSend(self->config->bus.wspi.drv, &cmd, 1, value);
507}
508#endif /* XSNOR_USE_WSPI == TRUE */
509
510/*===========================================================================*/
511/* Module exported functions. */
512/*===========================================================================*/
513
514/*===========================================================================*/
515/* Module class "hal_xsnor_macronix_mx25_c" methods. */
516/*===========================================================================*/
517
518/**
519 * @name Methods implementations of hal_xsnor_macronix_mx25_c
520 * @{
521 */
522/**
523 * @brief Implementation of object creation.
524 * @note This function is meant to be used by derived classes.
525 *
526 * @param[out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
527 * instance to be initialized.
528 * @param[in] vmt VMT pointer for the new object.
529 * @return A new reference to the object.
530 */
531void *__mx25_objinit_impl(void *ip, const void *vmt) {
533
534 /* Initialization of the ancestors-defined parts.*/
536
537 /* Initialization code.*/
538 self->descriptor.attributes = FLASH_ATTR_ERASED_IS_ONE |
541 self->descriptor.page_size = 256U;
542 self->descriptor.sectors_count = 0U; /* Overwritten.*/
543 self->descriptor.sectors = NULL;
544 self->descriptor.sectors_size = 0U;
545 self->descriptor.address = 0U;
546 self->descriptor.size = 0U; /* Overwritten.*/
547
548 return self;
549}
550
551/**
552 * @brief Implementation of object finalization.
553 * @note This function is meant to be used by derived classes.
554 *
555 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
556 * instance to be disposed.
557 */
558void __mx25_dispose_impl(void *ip) {
560
561 /* Finalization code.*/
562 /* Implementation.*/
563
564 /* Finalization of the ancestors-defined parts.*/
566}
567
568/**
569 * @brief Override of method @p xsnor_device_init().
570 *
571 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
572 * instance.
573 * @return An error code.
574 */
577 const xsnor_config_t *config = self->config;
578
579 /* Bus type and width setup, only necessary if WSPI is in use.*/
580#if XSNOR_USE_WSPI == TRUE
581 switch (config->bus_type) {
583 self->commands = NULL;
584 break;
586 if ((self->config->options &MX25_OPT_USE_DTR) != 0U) {
587 self->commands = &cmd_8dtr;
588 }
589 else {
590 self->commands = &cmd_8str;
591 }
592 break;
593 default:
594 osalDbgAssert(false, "invalid bus type");
595 self->commands = NULL;
597 }
598#endif
599
600#if XSNOR_USE_BOTH == TRUE
601 if (config->bus_type == XSNOR_BUS_MODE_SPI)
602#endif
603#if XSNOR_USE_SPI == TRUE
604 {
605 /* Initialization procedure in the SPI case.
606 Reading device ID.*/
608 3U, &config->buffers->databuf[0]);
609
610 /* Manufacturer identifier.*/
613 config->buffers->databuf[0])) {
615 }
616
617 /* Memory identifier.*/
620 config->buffers->databuf[1])) {
622 }
623 }
624#endif /* XSNOR_USE_SPI == TRUE */
625#if XSNOR_USE_BOTH == TRUE
626 else
627#endif
628#if XSNOR_USE_WSPI == TRUE
629 {
630 /* Attempting a reset of the device, it could be in an unexpected state
631 because a CPU reset does not reset the memory too.*/
632 mx25_reset_memory(self);
633
634 /* Reading device ID and unique ID.*/
635 mx25_read_id(self, &config->buffers->databuf[0]);
636
637 /* Manufacturer identifier.*/
640 config->buffers->databuf[0])) {
642 }
643
644 /* Memory identifier.*/
647 config->buffers->databuf[1])) {
649 }
650
651 /* Setting up dummy cycles, note this is a volatile-only setting.*/
652 config->buffers->databuf[4] = ~(((self->config->options & MX25_OPT_DUMMY_CYCLES_MASK) - 6U) / 2U) & 7U;
653 mx25_write_cr2(self, 0x00000300U, &config->buffers->databuf[4]);
654
655 /* Checking if the bus switch is needed, there are extra steps in
656 that case.*/
657 if ((self->config->options & MX25_OPT_NO_WIDTH_SWITCH) == 0U) {
658
659 /* Switching to final bus mode then reading the ID again for
660 confirmation.*/
661 switch (self->config->bus_type) {
663 {
664 static const uint8_t cr2_spi[1] = {0x00};
665 mx25_write_cr2(self, 0x00000000U, cr2_spi);
667 &config->buffers->databuf[16]);
668 }
669 break;
671 if ((self->config->options & MX25_OPT_USE_DTR) != 0U) {
672 static const uint8_t cr2_opi_dtr[1] = {0x02};
673 mx25_write_cr2(self, 0x00000000U, cr2_opi_dtr);
675 0U, 4U, 6U, /* Note: always 4 dummies.*/
676 &config->buffers->databuf[16]);
677
678 /* In DTR mode bytes are read twice, adjusting.*/
679 config->buffers->databuf[16 + 1] = config->buffers->databuf[16 + 2];
680 config->buffers->databuf[16 + 2] = config->buffers->databuf[16 + 4];
681 }
682 else {
683 static const uint8_t cr2_opi_str[1] = {0x01};
684 mx25_write_cr2(self, 0x00000000U, cr2_opi_str);
686 0U, 4U, 3U, /* Note: always 4 dummies.*/
687 &config->buffers->databuf[16]);
688 }
689 break;
690 default:
692 }
693
694 /* Comparing with the previously read ID.*/
695 if (memcmp(&config->buffers->databuf[0],
696 &config->buffers->databuf[16], 3) != 0U) {
698 }
699 }
700 }
701#endif /* XSNOR_USE_WSPI == TRUE */
702
703 /* Variable parts of the descriptor.*/
704 if ((self->config->options & MX25_OPT_USE_SUBSECTORS) != 0U) {
705 self->descriptor.sectors_size = 0x00001000U;
706 }
707 else {
708 self->descriptor.sectors_size = 0x00010000U;
709 }
710 self->descriptor.size = (uint32_t)(1U << ((size_t)config->buffers->databuf[2] & 0x1FU));
711 self->descriptor.sectors_count = self->descriptor.size / self->descriptor.sectors_size;
712
713 if (self->descriptor.size > 0x01000000U) {
714 self->descriptor.attributes |= FLASH_ATTR_SPI_4BYTES_ADDR_HINT;
715 }
716 else {
717 self->descriptor.attributes &= ~FLASH_ATTR_SPI_4BYTES_ADDR_HINT;
718 }
719
720 return FLASH_NO_ERROR;
721}
722
723/**
724 * @brief Override of method @p xsnor_device_read().
725 *
726 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
727 * instance.
728 * @param[in] offset Flash offset.
729 * @param[in] n Number of bytes to be read.
730 * @param[out] rp Pointer to the data buffer.
731 * @return An error code.
732 */
734 uint8_t *rp) {
736
737 /* Command depends on bus mode.*/
738 switch (self->config->bus_type) {
741 mx25_spi_4bytes(self) ?
743 offset, 8U, /* Always 8 dummies. */
744 n, rp);
745 break;
747 if ((self->config->options & MX25_OPT_USE_DTR) != 0U) {
749 self->config->options & MX25_OPT_DUMMY_CYCLES_MASK,
750 n, rp);
751 }
752 else {
754 self->config->options & MX25_OPT_DUMMY_CYCLES_MASK,
755 n, rp);
756 }
757 break;
758 default:
759 osalDbgAssert(false, "invalid bus type");
761 }
762
763 return FLASH_NO_ERROR;
764}
765
766/**
767 * @brief Override of method @p xsnor_device_program().
768 *
769 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
770 * instance.
771 * @param[in] offset Flash offset.
772 * @param[in] n Number of bytes to be programmed.
773 * @param[in] pp Pointer to the data buffer.
774 * @return An error code.
775 */
777 const uint8_t *pp) {
779
780 /* Data is programmed page by page.*/
781 while (n > 0U) {
782 flash_error_t err;
783
784 /* Data size that can be written in a single program page operation.*/
785 size_t chunk = (size_t)(((offset | PAGE_MASK) + 1U) - offset);
786 if (chunk > n) {
787 chunk = n;
788 }
789
790 /* Command depends on bus mode.*/
791 switch (self->config->bus_type) {
793 /* Enabling write operation.*/
795
796 /* Page program command.*/
798 mx25_spi_4bytes(self) ?
800 offset, chunk, pp);
801 break;
803 /* Enabling write operation.*/
805
806 /* Page program command.*/
807 __xsnor_bus_cmd_addr_send(self, CMD_OPI_PP, offset, chunk, pp);
808 break;
809 default:
810 osalDbgAssert(false, "invalid bus type");
812 }
813
814 /* Wait for status and check errors.*/
815 err = mx25_poll_status(self);
816 if (err != FLASH_NO_ERROR) {
817
818 return err;
819 }
820
821 /* Next page.*/
822 offset += chunk;
823 pp += chunk;
824 n -= chunk;
825 }
826
827 return FLASH_NO_ERROR;
828}
829
830/**
831 * @brief Override of method @p xsnor_device_start_erase_all().
832 *
833 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
834 * instance.
835 * @return An error code.
836 */
839
840 /* Command depends on bus mode.*/
841 switch (self->config->bus_type) {
843 /* Enabling write operation.*/
845
846 /* Bulk erase command.*/
848 break;
850 /* Enabling write operation.*/
852
853 /* Bulk erase command.*/
855 break;
856 default:
857 osalDbgAssert(false, "invalid bus type");
859 }
860
861 return FLASH_NO_ERROR;
862}
863
864/**
865 * @brief Override of method @p xsnor_device_start_erase_sector().
866 *
867 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
868 * instance.
869 * @param[in] sector Sector to be erased.
870 * @return An error code.
871 */
874 flash_offset_t offset = (flash_offset_t)(sector * self->descriptor.sectors_size);
875
876 /* Command depends on bus mode.*/
877 switch (self->config->bus_type) {
879 /* Enabling write operation.*/
881
882 /* Sector erase command.*/
883 if ((self->config->options & MX25_OPT_USE_SUBSECTORS) == 0U) {
885 mx25_spi_4bytes(self) ?
887 offset);
888 }
889 else {
891 mx25_spi_4bytes(self) ?
893 offset);
894 }
895 break;
897 /* Enabling write operation.*/
899
900 /* Sector erase command.*/
901 if ((self->config->options & MX25_OPT_USE_SUBSECTORS) == 0U) {
902 __xsnor_bus_cmd_addr(self, CMD_OPI_BE, offset);
903 }
904 else {
905 __xsnor_bus_cmd_addr(self, CMD_OPI_SE, offset);
906 }
907 break;
908 default:
909 osalDbgAssert(false, "invalid bus type");
911 }
912
913 return FLASH_NO_ERROR;
914}
915
916/**
917 * @brief Override of method @p xsnor_device_query_erase().
918 *
919 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
920 * instance.
921 * @param[out] msec Recommended time, in milliseconds, that should
922 * be spent before calling this function again,
923 * can be @p NULL
924 * @return An error code.
925 */
926flash_error_t __mx25_query_erase_impl(void *ip, unsigned *msec) {
928
929 /* Command depends on bus mode.*/
930 switch (self->config->bus_type) {
932 /* Reading SR.*/
934 &self->config->buffers->databuf[0]);
935
936 /* Reading SCUR.*/
938 &self->config->buffers->databuf[16]);
939 break;
941 /* Reading SR.*/
943 0U, 4U, 2U, /* Note: always 4 dummies.*/
944 &self->config->buffers->databuf[0]);
945
946 /* Reading SCUR.*/
948 0U, 4U, 2U, /* Note: always 4 dummies.*/
949 &self->config->buffers->databuf[16]);
950 break;
951 default:
952 osalDbgAssert(false, "invalid bus type");
954 }
955
956 /* If the WIP bit is one (busy) or the flash in a suspended state then
957 report that the operation is still in progress.*/
958 if (((self->config->buffers->databuf[0] & 1) != 0U) ||
959 ((self->config->buffers->databuf[16] & 8) != 0U)) {
960
961 /* Recommended time before polling again, this is a simplified
962 implementation.*/
963 if (msec != NULL) {
964 *msec = 1U;
965 }
966
967 return FLASH_BUSY_ERASING;
968 }
969
970 /* Checking for errors.*/
971 if ((self->config->buffers->databuf[16] & FLAGS_ALL_ERRORS) != 0U) {
972
973 /* Erase operation failed.*/
974 return FLASH_ERROR_ERASE;
975 }
976
977 return FLASH_NO_ERROR;
978}
979
980/**
981 * @brief Override of method @p xsnor_device_verify_erase().
982 *
983 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
984 * instance.
985 * @param[in] sector Sector to be verified.
986 * @return An error code.
987 */
990 flash_offset_t offset;
991 size_t n;
992
993 /* Read command.*/
994 offset = (flash_offset_t)(sector * self->descriptor.sectors_size);
995 n = self->descriptor.sectors_size;
996 while (n > 0U) {
997 uint8_t *p;
998
999 __mx25_read_impl(self, offset,
1000 XSNOR_BUFFER_SIZE, &self->config->buffers->databuf[0]);
1001
1002 /* Checking for erased state of current buffer.*/
1003 for (p = &self->config->buffers->databuf[0];
1004 p < &self->config->buffers->databuf[XSNOR_BUFFER_SIZE];
1005 p++) {
1006
1007 if (*p != 0xFFU) {
1008 return FLASH_ERROR_VERIFY;
1009 }
1010 }
1011
1012 offset += XSNOR_BUFFER_SIZE;
1013 n -= XSNOR_BUFFER_SIZE;
1014 }
1015
1016 return FLASH_NO_ERROR;
1017}
1018
1019/**
1020 * @brief Override of method @p xsnor_device_mmap_on().
1021 *
1022 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
1023 * instance.
1024 * @param[out] addrp Pointer to the memory mapped memory or @p NULL
1025 * @return An error code.
1026 */
1027flash_error_t __mx25_mmap_on_impl(void *ip, uint8_t **addrp) {
1029
1030#if XSNOR_USE_BOTH == TRUE
1031 if (self->config->bus_type == XSNOR_BUS_MODE_SPI) {
1033 }
1034#endif
1035
1036#if XSNOR_USE_WSPI == FALSE
1038#else /* XSNOR_USE_WSPI == TRUE */
1039 {
1040 wspi_command_t cmd;
1041
1042 /* Bus acquisition.*/
1043 __xsnor_bus_acquire(self);
1044
1045 /* Command depends on bus mode.*/
1046 switch (self->config->bus_type) {
1047 case XSNOR_BUS_MODE_SPI:
1050 cmd.dummy = 8U; /* Note, always 8 for this command.*/
1051 break;
1053 if ((self->config->options & MX25_OPT_USE_DTR) != 0U) {
1055 cmd.cmd = CMD_OPI_8DTRD;
1056 }
1057 else {
1059 cmd.cmd = CMD_OPI_8READ;
1060 }
1061 cmd.dummy = (uint32_t)(self->config->options & MX25_OPT_DUMMY_CYCLES_MASK);
1062 break;
1063 default:
1064 osalDbgAssert(false, "invalid bus type");
1066 }
1067 cmd.addr = 0U;
1068 cmd.alt = 0U;
1069 wspiMapFlash(self->config->bus.wspi.drv, &cmd, addrp);
1070
1071 /* Bus release.*/
1072 __xsnor_bus_release(self);
1073
1074 return FLASH_NO_ERROR;
1075 }
1076#endif
1077}
1078
1079/**
1080 * @brief Override of method @p xsnor_device_mmap_off().
1081 *
1082 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
1083 * instance.
1084 */
1085void __mx25_mmap_off_impl(void *ip) {
1087
1088#if XSNOR_USE_WSPI == TRUE
1089 /* Bus acquisition.*/
1090 __xsnor_bus_acquire(self);
1091
1092 /* Stopping WSPI memory mapped mode.*/
1093 wspiUnmapFlash(self->config->bus.wspi.drv);
1094
1095 /* Bus release.*/
1096 __xsnor_bus_release(self);
1097#endif
1098}
1099/** @} */
1100
1101/**
1102 * @brief VMT structure of SNOR Macronix MX25 driver class.
1103 * @note It is public because accessed by the inlined constructor.
1104 */
1106 .dispose = __mx25_dispose_impl,
1107 .init = __mx25_init_impl,
1108 .read = __mx25_read_impl,
1109 .program = __mx25_program_impl,
1110 .start_erase_all = __mx25_start_erase_all_impl,
1111 .start_erase_sector = __mx25_start_erase_sector_impl,
1112 .query_erase = __mx25_query_erase_impl,
1113 .verify_erase = __mx25_verify_erase_impl,
1114 .mmap_on = __mx25_mmap_on_impl,
1115 .mmap_off = __mx25_mmap_off_impl
1116};
1117
1118/** @} */
static const struct EFlashDriverVMT vmt
Definition hal_efl.c:71
uint32_t flash_sector_t
Type of a flash sector number.
Definition hal_flash.h:117
uint32_t flash_offset_t
Type of a flash offset.
Definition hal_flash.h:112
#define FLASH_ATTR_REWRITABLE
Programmed pages can be programmed again.
Definition hal_flash.h:48
#define FLASH_ATTR_SUSPEND_ERASE_CAPABLE
The device is able to suspend erase operations.
Definition hal_flash.h:68
flash_error_t
Type of a flash error code.
Definition hal_flash.h:98
#define FLASH_ATTR_ERASED_IS_ONE
Defines one as the erased bit state.
Definition hal_flash.h:39
@ FLASH_ERROR_ERASE
Definition hal_flash.h:103
@ FLASH_ERROR_HW_FAILURE
Definition hal_flash.h:105
@ FLASH_BUSY_ERASING
Definition hal_flash.h:100
@ FLASH_ERROR_UNIMPLEMENTED
Definition hal_flash.h:106
@ FLASH_ERROR_PROGRAM
Definition hal_flash.h:102
@ FLASH_ERROR_VERIFY
Definition hal_flash.h:104
@ FLASH_NO_ERROR
Definition hal_flash.h:99
#define FLASH_ATTR_SPI_4BYTES_ADDR_HINT
Hint to use 4 bytes addresses in SPI protocol.
void __xsnor_dispose_impl(void *ip)
Implementation of object finalization.
#define XSNOR_BUFFER_SIZE
Non-cacheable operations buffer.
#define __xsnor_bus_release(self)
#define XSNOR_BUS_MODE_SPI
void * __xsnor_objinit_impl(void *ip, const void *vmt)
Implementation of object creation.
#define XSNOR_BUS_MODE_WSPI_8LINES
void __xsnor_bus_cmd_addr_send(void *ip, uint32_t cmd, flash_offset_t offset, size_t n, const uint8_t *p)
Sends a command followed by a flash address and a data transmit phase.
void __xsnor_bus_cmd_addr(void *ip, uint32_t cmd, flash_offset_t offset)
Sends a command followed by a flash address.
void __xsnor_bus_cmd(void *ip, uint32_t cmd)
Sends a naked command.
struct xsnor_config xsnor_config_t
Type of a SNOR configuration structure.
void __xsnor_bus_cmd_addr_dummy_receive(void *ip, uint32_t cmd, flash_offset_t offset, uint32_t dummy, size_t n, uint8_t *p)
Sends a complete header followed by a data receive phase.
void __xsnor_bus_cmd_receive(void *ip, uint32_t cmd, size_t n, uint8_t *p)
Sends a command followed by a data receive phase.
struct xsnor_commands xsnor_commands_t
Type of a commands configuration structure.
#define __xsnor_bus_acquire(self)
static const xsnor_commands_t cmd_8dtr
#define CMD_SPI_FAST_READ3B
#define CFG_C16_A32_DATA_8DTR
flash_error_t __mx25_mmap_on_impl(void *ip, uint8_t **addrp)
Override of method xsnor_device_mmap_on().
#define CFG_C16_A32_8DTR
#define CMD_SPI_FAST_READ4B
void __mx25_mmap_off_impl(void *ip)
Override of method xsnor_device_mmap_off().
static void mx25_write_cr2(hal_xsnor_macronix_mx25_c *self, uint32_t addr, const uint8_t *value)
static const wspi_command_t cmd_reset_enable_8dtr
static const wspi_command_t cmd_reset_memory_spi
static void mx25_read_id(hal_xsnor_macronix_mx25_c *self, uint8_t *buf)
static bool mx25_find_id(const uint8_t *set, size_t size, uint8_t element)
#define CFG_C16_DATA_8STR
static const wspi_command_t cmd_reset_memory_8dtr
static const wspi_command_t cmd_reset_enable_spi
static void mx25_reset_memory(hal_xsnor_macronix_mx25_c *self)
#define CMD_SPI_WRCR2
flash_error_t __mx25_query_erase_impl(void *ip, unsigned *msec)
Override of method xsnor_device_query_erase().
#define MX25_OPT_NO_WIDTH_SWITCH
Switch bus width on initialization.
static const uint8_t mx25_memory_type_ids[]
#define MX25_OPT_DUMMY_CYCLES_MASK
Mask of the dummy cycles field.
#define CMD_SPI_RSTEN
static bool mx25_spi_4bytes(const hal_xsnor_macronix_mx25_c *self)
#define CFG_C8_A32_DATA_SPI
#define MX25_OPT_USE_SUBSECTORS
Use 4kB sub-sectors rather than 64kB sectors.
static const wspi_command_t cmd_reset_enable_8str
void __mx25_dispose_impl(void *ip)
Implementation of object finalization.
#define CFG_C8_DATA_SPI
flash_error_t __mx25_program_impl(void *ip, flash_offset_t offset, size_t n, const uint8_t *pp)
Override of method xsnor_device_program().
static flash_error_t mx25_poll_status(hal_xsnor_macronix_mx25_c *self)
flash_error_t __mx25_start_erase_sector_impl(void *ip, flash_sector_t sector)
Override of method xsnor_device_start_erase_sector().
static const wspi_command_t cmd_reset_memory_8str
#define CFG_C16_A32_DATA_8STR
flash_error_t __mx25_read_impl(void *ip, flash_offset_t offset, size_t n, uint8_t *rp)
Override of method xsnor_device_read().
flash_error_t __mx25_init_impl(void *ip)
Override of method xsnor_device_init().
#define CFG_C16_DATA_8DTR
const struct hal_xsnor_macronix_mx25_vmt __hal_xsnor_macronix_mx25_vmt
VMT structure of SNOR Macronix MX25 driver class.
#define MX25_OPT_NICE_WAITING
Delays insertion.
flash_error_t __mx25_start_erase_all_impl(void *ip)
Override of method xsnor_device_start_erase_all().
#define CMD_OPI_8DTRD
flash_error_t __mx25_verify_erase_impl(void *ip, flash_sector_t sector)
Override of method xsnor_device_verify_erase().
static const xsnor_commands_t cmd_spi
#define CMD_SPI_RDSCUR
#define CMD_OPI_8READ
static const uint8_t mx25_manufacturer_ids[]
void * __mx25_objinit_impl(void *ip, const void *vmt)
Implementation of object creation.
static const xsnor_commands_t cmd_8str
#define FLAGS_ALL_ERRORS
#define MX25_OPT_USE_DTR
Enables DTR in 8 lines mode.
#define CFG_C16_A32_8STR
#define osalThreadSleepMicroseconds(usecs)
Delays the invoking thread for the specified number of microseconds.
Definition osal.h:535
#define osalDbgAssert(c, remark)
Condition assertion.
Definition osal.h:264
#define osalThreadSleepMilliseconds(msecs)
Delays the invoking thread for the specified number of milliseconds.
Definition osal.h:522
void wspiMapFlash(WSPIDriver *wspip, const wspi_command_t *cmdp, uint8_t **addrp)
Maps in memory space a WSPI flash device.
Definition hal_wspi.c:346
bool wspiReceive(WSPIDriver *wspip, const wspi_command_t *cmdp, size_t n, uint8_t *rxbuf)
Sends a command then receives data over the WSPI bus.
Definition hal_wspi.c:311
bool wspiCommand(WSPIDriver *wspip, const wspi_command_t *cmdp)
Sends a command without data phase.
Definition hal_wspi.c:237
bool wspiSend(WSPIDriver *wspip, const wspi_command_t *cmdp, size_t n, const uint8_t *txbuf)
Sends a command with data over the WSPI bus.
Definition hal_wspi.c:273
void wspiUnmapFlash(WSPIDriver *wspip)
Unmaps from memory space a WSPI flash device.
Definition hal_wspi.c:372
Class hal_xsnor_macronix_mx25_c virtual methods table.
Type of a WSPI command descriptor.
Definition hal_wspi.h:101
uint32_t dummy
Number of dummy cycles to be inserted.
Definition hal_wspi.h:121
uint32_t cfg
Transfer configuration field.
Definition hal_wspi.h:105
uint32_t alt
Alternate phase data.
Definition hal_wspi.h:117
uint32_t addr
Address phase data.
Definition hal_wspi.h:113
uint32_t cmd
Command phase data.
Definition hal_wspi.h:109
uint8_t databuf[XSNOR_BUFFER_SIZE]
Non-cacheable data buffer.
int bus_type
Bus type selection switch.
xsnor_buffers_t * buffers
Pointer to the non-cacheable buffers.