ChibiOS/HAL 9.0.0
hal_xsnor_macronix_mx25_impl.inc
Go to the documentation of this file.
1/*
2 ChibiOS - Copyright (C) 2006..2025 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
372#if (XSNOR_USE_WSPI == TRUE) || defined(__DOXYGEN__)
374
375 /* If the device is in one bit mode then the following commands are
376 rejected because shorter than 8 bits. If the device is in multiple
377 bits mode then the commands are accepted and the device is reset to
378 one bit mode.*/
379 if ((self->config->options &MX25_OPT_USE_DTR) != 0U) {
380 wspiCommand(self->config->bus.wspi.drv, &cmd_reset_enable_8dtr);
381 wspiCommand(self->config->bus.wspi.drv, &cmd_reset_memory_8dtr);
382 }
383 else {
384 wspiCommand(self->config->bus.wspi.drv, &cmd_reset_enable_8str);
385 wspiCommand(self->config->bus.wspi.drv, &cmd_reset_memory_8str);
386 }
387
388 /* Now the device should be in one bit mode for sure and we perform a
389 device reset.*/
390 wspiCommand(self->config->bus.wspi.drv, &cmd_reset_enable_spi);
391 wspiCommand(self->config->bus.wspi.drv, &cmd_reset_memory_spi);
392
393 /* The device requires at least 10uS to recover after a reset, it could
394 need up to 100mS in cause a reset occurred during a chip erase, 50uS
395 covers most cases.*/
397}
398
399static void mx25_read_id(hal_xsnor_macronix_mx25_c *self, uint8_t *buf) {
400 wspi_command_t cmd;
401
402 if ((self->config->options & MX25_OPT_NO_WIDTH_SWITCH) != 0U) {
403 /* Not switching, assuming it is already in final bus mode.*/
404 switch (self->config->bus_type) {
406 cmd.cfg = CFG_C8_DATA_SPI;
407 cmd.cmd = CMD_SPI_RDID;
408 break;
410 if ((self->config->options & MX25_OPT_USE_DTR) != 0U) {
412 }
413 else {
415 }
416 cmd.cmd = CMD_OPI_RDID;
417 break;
418 default:
419 osalDbgAssert(false, "invalid bus type");
420 buf[0] = 0;
421 buf[1] = 0;
422 buf[2] = 0;
423 return;
424 }
425 }
426 else {
427 /* It is post-reset, before going to switch, assuming SPI.*/
428 cmd.cfg = CFG_C8_DATA_SPI;
429 cmd.cmd = CMD_SPI_RDID;
430 }
431 cmd.addr = 0U;
432 cmd.alt = 0U;
433 cmd.dummy = 0U;
434 wspiReceive(self->config->bus.wspi.drv, &cmd, 3U, buf);
435}
436
438 uint32_t addr, const uint8_t *value) {
439 wspi_command_t cmd;
440
441 if ((self->config->options & MX25_OPT_NO_WIDTH_SWITCH) != 0U) {
442 /* Not switching, assuming it is already in final bus mode.*/
443 switch (self->config->bus_type) {
445 cmd.cfg = CFG_C8_SPI;
446 cmd.cmd = CMD_SPI_WREN;
447 break;
449 if ((self->config->options & MX25_OPT_USE_DTR) != 0U) {
450 cmd.cfg = CFG_C16_8DTR;
451 }
452 else {
453 cmd.cfg = CFG_C16_8STR;
454 }
455 cmd.cmd = CMD_OPI_WREN;
456 break;
457 default:
458 osalDbgAssert(false, "invalid bus type");
459 return;
460 }
461 }
462 else {
463 /* It is post-reset, before going to switch, assuming SPI.*/
464 cmd.cfg = CFG_C8_SPI;
465 cmd.cmd = CMD_SPI_WREN;
466 }
467 cmd.addr = 0U;
468 cmd.alt = 0U;
469 cmd.dummy = 0U;
470 wspiCommand(self->config->bus.wspi.drv, &cmd);
471
472 if ((self->config->options & MX25_OPT_NO_WIDTH_SWITCH) != 0U) {
473 /* Not switching, assuming it is already in final bus mode.*/
474 switch (self->config->bus_type) {
477 cmd.cmd = CMD_SPI_WRCR2;
478 break;
480 if ((self->config->options & MX25_OPT_USE_DTR) != 0U) {
482 }
483 else {
485 }
486 cmd.cmd = CMD_OPI_WRCR2;
487 break;
488 default:
489 osalDbgAssert(false, "invalid bus type");
490 return;
491 }
492 }
493 else {
494 /* It is post-reset, before going to switch, assuming SPI.*/
496 cmd.cmd = CMD_SPI_WRCR2;
497 }
498 cmd.addr = addr;
499 cmd.alt = 0U;
500 cmd.dummy = 0U;
501 wspiSend(self->config->bus.wspi.drv, &cmd, 1, value);
502}
503#endif /* XSNOR_USE_WSPI == TRUE */
504
505/*===========================================================================*/
506/* Module exported functions. */
507/*===========================================================================*/
508
509/*===========================================================================*/
510/* Module class "hal_xsnor_macronix_mx25_c" methods. */
511/*===========================================================================*/
512
513/**
514 * @name Methods implementations of hal_xsnor_macronix_mx25_c
515 * @{
516 */
517/**
518 * @brief Implementation of object creation.
519 * @note This function is meant to be used by derived classes.
520 *
521 * @param[out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
522 * instance to be initialized.
523 * @param[in] vmt VMT pointer for the new object.
524 * @return A new reference to the object.
525 */
526void *__mx25_objinit_impl(void *ip, const void *vmt) {
528
529 /* Initialization of the ancestors-defined parts.*/
531
532 /* Initialization code.*/
533 self->descriptor.attributes = FLASH_ATTR_ERASED_IS_ONE |
536 self->descriptor.page_size = 256U;
537 self->descriptor.sectors_count = 0U; /* Overwritten.*/
538 self->descriptor.sectors = NULL;
539 self->descriptor.sectors_size = 0U;
540 self->descriptor.address = 0U;
541 self->descriptor.size = 0U; /* Overwritten.*/
542
543 return self;
544}
545
546/**
547 * @brief Implementation of object finalization.
548 * @note This function is meant to be used by derived classes.
549 *
550 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
551 * instance to be disposed.
552 */
553void __mx25_dispose_impl(void *ip) {
555
556 /* Finalization code.*/
557 /* Implementation.*/
558
559 /* Finalization of the ancestors-defined parts.*/
561}
562
563/**
564 * @brief Override of method @p xsnor_device_init().
565 *
566 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
567 * instance.
568 * @return An error code.
569 */
572 const xsnor_config_t *config = self->config;
573
574 /* Bus type and width setup, only necessary if WSPI is in use.*/
575#if XSNOR_USE_WSPI == TRUE
576 switch (config->bus_type) {
578 self->commands = NULL;
579 break;
581 if ((self->config->options &MX25_OPT_USE_DTR) != 0U) {
582 self->commands = &cmd_8dtr;
583 }
584 else {
585 self->commands = &cmd_8str;
586 }
587 break;
588 default:
589 osalDbgAssert(false, "invalid bus type");
590 self->commands = NULL;
592 }
593#endif
594
595#if XSNOR_USE_BOTH == TRUE
596 if (config->bus_type == XSNOR_BUS_MODE_SPI)
597#endif
598#if XSNOR_USE_SPI == TRUE
599 {
600 /* Initialization procedure in the SPI case.
601 Reading device ID.*/
603 3U, &config->buffers->databuf[0]);
604
605 /* Manufacturer identifier.*/
608 config->buffers->databuf[0])) {
610 }
611
612 /* Memory identifier.*/
615 config->buffers->databuf[1])) {
617 }
618 }
619#endif /* XSNOR_USE_SPI == TRUE */
620#if XSNOR_USE_BOTH == TRUE
621 else
622#endif
623#if XSNOR_USE_WSPI == TRUE
624 {
625 /* Attempting a reset of the device, it could be in an unexpected state
626 because a CPU reset does not reset the memory too.*/
627 mx25_reset_memory(self);
628
629 /* Reading device ID and unique ID.*/
630 mx25_read_id(self, &config->buffers->databuf[0]);
631
632 /* Manufacturer identifier.*/
635 config->buffers->databuf[0])) {
637 }
638
639 /* Memory identifier.*/
642 config->buffers->databuf[1])) {
644 }
645
646 /* Setting up dummy cycles, note this is a volatile-only setting.*/
647 config->buffers->databuf[4] = ~(((self->config->options & MX25_OPT_DUMMY_CYCLES_MASK) - 6U) / 2U) & 7U;
648 mx25_write_cr2(self, 0x00000300U, &config->buffers->databuf[4]);
649
650 /* Checking if the bus switch is needed, there are extra steps in
651 that case.*/
652 if ((self->config->options & MX25_OPT_NO_WIDTH_SWITCH) == 0U) {
653
654 /* Switching to final bus mode then reading the ID again for
655 confirmation.*/
656 switch (self->config->bus_type) {
658 {
659 static const uint8_t cr2_spi[1] = {0x00};
660 mx25_write_cr2(self, 0x00000000U, cr2_spi);
662 &config->buffers->databuf[16]);
663 }
664 break;
666 if ((self->config->options & MX25_OPT_USE_DTR) != 0U) {
667 static const uint8_t cr2_opi_dtr[1] = {0x02};
668 mx25_write_cr2(self, 0x00000000U, cr2_opi_dtr);
670 0U, 4U, 6U, /* Note: always 4 dummies.*/
671 &config->buffers->databuf[16]);
672
673 /* In DTR mode bytes are read twice, adjusting.*/
674 config->buffers->databuf[16 + 1] = config->buffers->databuf[16 + 2];
675 config->buffers->databuf[16 + 2] = config->buffers->databuf[16 + 4];
676 }
677 else {
678 static const uint8_t cr2_opi_str[1] = {0x01};
679 mx25_write_cr2(self, 0x00000000U, cr2_opi_str);
681 0U, 4U, 3U, /* Note: always 4 dummies.*/
682 &config->buffers->databuf[16]);
683 }
684 break;
685 default:
687 }
688
689 /* Comparing with the previously read ID.*/
690 if (memcmp(&config->buffers->databuf[0],
691 &config->buffers->databuf[16], 3) != 0U) {
693 }
694 }
695 }
696#endif /* XSNOR_USE_WSPI == TRUE */
697
698 /* Variable parts of the descriptor.*/
699 if ((self->config->options & MX25_OPT_USE_SUBSECTORS) != 0U) {
700 self->descriptor.sectors_size = 0x00001000U;
701 }
702 else {
703 self->descriptor.sectors_size = 0x00010000U;
704 }
705 self->descriptor.size = (uint32_t)(1U << ((size_t)config->buffers->databuf[2] & 0x1FU));
706 self->descriptor.sectors_count = self->descriptor.size / self->descriptor.sectors_size;
707
708 return FLASH_NO_ERROR;
709}
710
711/**
712 * @brief Override of method @p xsnor_device_read().
713 *
714 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
715 * instance.
716 * @param[in] offset Flash offset.
717 * @param[in] n Number of bytes to be read.
718 * @param[out] rp Pointer to the data buffer.
719 * @return An error code.
720 */
722 uint8_t *rp) {
724
725 /* Command depends on bus mode.*/
726 switch (self->config->bus_type) {
729 offset, 8U, /* Always 8 dummies. */
730 n, rp);
731 break;
733 if ((self->config->options & MX25_OPT_USE_DTR) != 0U) {
735 self->config->options & MX25_OPT_DUMMY_CYCLES_MASK,
736 n, rp);
737 }
738 else {
740 self->config->options & MX25_OPT_DUMMY_CYCLES_MASK,
741 n, rp);
742 }
743 break;
744 default:
745 osalDbgAssert(false, "invalid bus type");
747 }
748
749 return FLASH_NO_ERROR;
750}
751
752/**
753 * @brief Override of method @p xsnor_device_program().
754 *
755 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
756 * instance.
757 * @param[in] offset Flash offset.
758 * @param[in] n Number of bytes to be programmed.
759 * @param[in] pp Pointer to the data buffer.
760 * @return An error code.
761 */
763 const uint8_t *pp) {
765
766 /* Data is programmed page by page.*/
767 while (n > 0U) {
768 flash_error_t err;
769
770 /* Data size that can be written in a single program page operation.*/
771 size_t chunk = (size_t)(((offset | PAGE_MASK) + 1U) - offset);
772 if (chunk > n) {
773 chunk = n;
774 }
775
776 /* Command depends on bus mode.*/
777 switch (self->config->bus_type) {
779 /* Enabling write operation.*/
781
782 /* Page program command.*/
783 __xsnor_bus_cmd_addr_send(self, CMD_SPI_PP4B, offset, chunk, pp);
784 break;
786 /* Enabling write operation.*/
788
789 /* Page program command.*/
790 __xsnor_bus_cmd_addr_send(self, CMD_OPI_PP, offset, chunk, pp);
791 break;
792 default:
793 osalDbgAssert(false, "invalid bus type");
795 }
796
797 /* Wait for status and check errors.*/
798 err = mx25_poll_status(self);
799 if (err != FLASH_NO_ERROR) {
800
801 return err;
802 }
803
804 /* Next page.*/
805 offset += chunk;
806 pp += chunk;
807 n -= chunk;
808 }
809
810 return FLASH_NO_ERROR;
811}
812
813/**
814 * @brief Override of method @p xsnor_device_start_erase_all().
815 *
816 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
817 * instance.
818 * @return An error code.
819 */
822
823 /* Command depends on bus mode.*/
824 switch (self->config->bus_type) {
826 /* Enabling write operation.*/
828
829 /* Bulk erase command.*/
831 break;
833 /* Enabling write operation.*/
835
836 /* Bulk erase command.*/
838 break;
839 default:
840 osalDbgAssert(false, "invalid bus type");
842 }
843
844 return FLASH_NO_ERROR;
845}
846
847/**
848 * @brief Override of method @p xsnor_device_start_erase_sector().
849 *
850 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
851 * instance.
852 * @param[in] sector Sector to be erased.
853 * @return An error code.
854 */
857 flash_offset_t offset = (flash_offset_t)(sector * self->descriptor.sectors_size);
858
859 /* Command depends on bus mode.*/
860 switch (self->config->bus_type) {
862 /* Enabling write operation.*/
864
865 /* Sector erase command.*/
866 if ((self->config->options & MX25_OPT_USE_SUBSECTORS) == 0U) {
867 __xsnor_bus_cmd_addr(self, CMD_SPI_BE4B, offset);
868 }
869 else {
870 __xsnor_bus_cmd_addr(self, CMD_SPI_SE4B, offset);
871 }
872 break;
874 /* Enabling write operation.*/
876
877 /* Sector erase command.*/
878 if ((self->config->options & MX25_OPT_USE_SUBSECTORS) == 0U) {
879 __xsnor_bus_cmd_addr(self, CMD_OPI_BE, offset);
880 }
881 else {
882 __xsnor_bus_cmd_addr(self, CMD_OPI_SE, offset);
883 }
884 break;
885 default:
886 osalDbgAssert(false, "invalid bus type");
888 }
889
890 return FLASH_NO_ERROR;
891}
892
893/**
894 * @brief Override of method @p xsnor_device_query_erase().
895 *
896 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
897 * instance.
898 * @param[out] msec Recommended time, in milliseconds, that should
899 * be spent before calling this function again,
900 * can be @p NULL
901 * @return An error code.
902 */
903flash_error_t __mx25_query_erase_impl(void *ip, unsigned *msec) {
905
906 /* Command depends on bus mode.*/
907 switch (self->config->bus_type) {
909 /* Reading SR.*/
911 &self->config->buffers->databuf[0]);
912
913 /* Reading SCUR.*/
915 &self->config->buffers->databuf[16]);
916 break;
918 /* Reading SR.*/
920 0U, 4U, 2U, /* Note: always 4 dummies.*/
921 &self->config->buffers->databuf[0]);
922
923 /* Reading SCUR.*/
925 0U, 4U, 2U, /* Note: always 4 dummies.*/
926 &self->config->buffers->databuf[16]);
927 break;
928 default:
929 osalDbgAssert(false, "invalid bus type");
931 }
932
933 /* If the WIP bit is one (busy) or the flash in a suspended state then
934 report that the operation is still in progress.*/
935 if (((self->config->buffers->databuf[0] & 1) != 0U) ||
936 ((self->config->buffers->databuf[16] & 8) != 0U)) {
937
938 /* Recommended time before polling again, this is a simplified
939 implementation.*/
940 if (msec != NULL) {
941 *msec = 1U;
942 }
943
944 return FLASH_BUSY_ERASING;
945 }
946
947 /* Checking for errors.*/
948 if ((self->config->buffers->databuf[16] & FLAGS_ALL_ERRORS) != 0U) {
949
950 /* Erase operation failed.*/
951 return FLASH_ERROR_ERASE;
952 }
953
954 return FLASH_NO_ERROR;
955}
956
957/**
958 * @brief Override of method @p xsnor_device_verify_erase().
959 *
960 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
961 * instance.
962 * @param[in] sector Sector to be verified.
963 * @return An error code.
964 */
967 flash_offset_t offset;
968 size_t n;
969
970 /* Read command.*/
971 offset = (flash_offset_t)(sector * self->descriptor.sectors_size);
972 n = self->descriptor.sectors_size;
973 while (n > 0U) {
974 uint8_t *p;
975
976 __mx25_read_impl(self, offset,
977 XSNOR_BUFFER_SIZE, &self->config->buffers->databuf[0]);
978
979 /* Checking for erased state of current buffer.*/
980 for (p = &self->config->buffers->databuf[0];
981 p < &self->config->buffers->databuf[XSNOR_BUFFER_SIZE];
982 p++) {
983
984 if (*p != 0xFFU) {
985 return FLASH_ERROR_VERIFY;
986 }
987 }
988
989 offset += XSNOR_BUFFER_SIZE;
991 }
992
993 return FLASH_NO_ERROR;
994}
995
996/**
997 * @brief Override of method @p xsnor_device_mmap_on().
998 *
999 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
1000 * instance.
1001 * @param[out] addrp Pointer to the memory mapped memory or @p NULL
1002 * @return An error code.
1003 */
1004flash_error_t __mx25_mmap_on_impl(void *ip, uint8_t **addrp) {
1006
1007#if XSNOR_USE_BOTH == TRUE
1008 if (self->config->bus_type == XSNOR_BUS_MODE_SPI) {
1010 }
1011#endif
1012
1013#if XSNOR_USE_WSPI == FALSE
1015#else /* XSNOR_USE_WSPI == TRUE */
1016 {
1017 wspi_command_t cmd;
1018
1019 /* Bus acquisition.*/
1020 __xsnor_bus_acquire(self);
1021
1022 /* Command depends on bus mode.*/
1023 switch (self->config->bus_type) {
1024 case XSNOR_BUS_MODE_SPI:
1027 cmd.dummy = 8U; /* Note, always 8 for this command.*/
1028 break;
1030 if ((self->config->options & MX25_OPT_USE_DTR) != 0U) {
1032 cmd.cmd = CMD_OPI_8DTRD;
1033 }
1034 else {
1036 cmd.cmd = CMD_OPI_8READ;
1037 }
1038 cmd.dummy = (uint32_t)(self->config->options & MX25_OPT_DUMMY_CYCLES_MASK);
1039 break;
1040 default:
1041 osalDbgAssert(false, "invalid bus type");
1043 }
1044 cmd.addr = 0U;
1045 cmd.alt = 0U;
1046 wspiMapFlash(self->config->bus.wspi.drv, &cmd, addrp);
1047
1048 /* Bus release.*/
1049 __xsnor_bus_release(self);
1050
1051 return FLASH_NO_ERROR;
1052 }
1053#endif
1054}
1055
1056/**
1057 * @brief Override of method @p xsnor_device_mmap_off().
1058 *
1059 * @param[in,out] ip Pointer to a @p hal_xsnor_macronix_mx25_c
1060 * instance.
1061 */
1062void __mx25_mmap_off_impl(void *ip) {
1064
1065#if XSNOR_USE_WSPI == TRUE
1066 /* Bus acquisition.*/
1067 __xsnor_bus_acquire(self);
1068
1069 /* Stopping WSPI memory mapped mode.*/
1070 wspiUnmapFlash(self->config->bus.wspi.drv);
1071
1072 /* Bus release.*/
1073 __xsnor_bus_release(self);
1074#endif
1075}
1076/** @} */
1077
1078/**
1079 * @brief VMT structure of SNOR Macronix MX25 driver class.
1080 * @note It is public because accessed by the inlined constructor.
1081 */
1083 .dispose = __mx25_dispose_impl,
1084 .init = __mx25_init_impl,
1085 .read = __mx25_read_impl,
1086 .program = __mx25_program_impl,
1087 .start_erase_all = __mx25_start_erase_all_impl,
1088 .start_erase_sector = __mx25_start_erase_sector_impl,
1089 .query_erase = __mx25_query_erase_impl,
1090 .verify_erase = __mx25_verify_erase_impl,
1091 .mmap_on = __mx25_mmap_on_impl,
1092 .mmap_off = __mx25_mmap_off_impl
1093};
1094
1095/** @} */
1096
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
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 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
#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.