Skip to content

Commit 037f994

Browse files
rodrigobrochadogalak
authored andcommitted
drivers: flash: Add workaround for anomaly 122 on nrf52840
The energy consumption on nrf52840 is unnecessarily high when CONFIG_NORDIC_QSPI_NOR is used due to Anomaly 122. The nrf_qspi_nor driver is unitialize after QSPI usage and initialize before using it again. Semaphore objects are used to allow multiple threads exclusive access and efficient usage. The main assumption made was that all QSPI API is stateless, in the sense that it is not required to store any peripheral state before uninit. Also, the QSPI driver was supposed to be synchronous, except for the erase operation, in which the nrf signals its start, instead of its end. While the flash is performing the erase, an uninit followed by an init doesn't work. For that reason, polling is done before every uninit. Tests were made with a simple LittleFS application in a custom board using flash MX25R3235F and another with the LittleFS flash sample using nrf52840 DK that has a MX25R6435F. Current consumption dropped from 630 uA to ~10uA in both cases. Signed-off-by: Rodrigo Brochado <[email protected]>
1 parent e845878 commit 037f994

File tree

1 file changed

+132
-7
lines changed

1 file changed

+132
-7
lines changed

drivers/flash/nrf_qspi_nor.c

Lines changed: 132 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ struct qspi_nor_config {
2626
uint32_t size;
2727
};
2828

29+
/* Main config structure */
30+
static nrfx_qspi_config_t QSPIconfig;
31+
2932
/* Status register bits */
3033
#define QSPI_SECTOR_SIZE SPI_NOR_SECTOR_SIZE
3134
#define QSPI_BLOCK_SIZE SPI_NOR_BLOCK_SIZE
@@ -50,6 +53,18 @@ BUILD_ASSERT(((INST_0_QER == JESD216_DW15_QER_NONE)
5053
|| (INST_0_QER == JESD216_DW15_QER_S1B6)),
5154
"Driver only supports NONE or S1B6 for quad-enable-requirements");
5255

56+
#if NRF52_ERRATA_122_PRESENT
57+
#include <hal/nrf_gpio.h>
58+
static int anomaly_122_init(const struct device *dev);
59+
static void anomaly_122_uninit(const struct device *dev);
60+
61+
#define ANOMALY_122_INIT(dev) anomaly_122_init(dev)
62+
#define ANOMALY_122_UNINIT(dev) anomaly_122_uninit(dev)
63+
#else
64+
#define ANOMALY_122_INIT(dev) 0
65+
#define ANOMALY_122_UNINIT(dev)
66+
#endif
67+
5368
#define WORD_SIZE 4
5469

5570
LOG_MODULE_REGISTER(qspi_nor, CONFIG_FLASH_LOG_LEVEL);
@@ -98,6 +113,10 @@ struct qspi_nor_data {
98113
struct k_sem sem;
99114
/* The semaphore to indicate that transfer has completed. */
100115
struct k_sem sync;
116+
#if NRF52_ERRATA_122_PRESENT
117+
/* The semaphore to control driver init/uninit. */
118+
struct k_sem count;
119+
#endif
101120
#else /* CONFIG_MULTITHREADING */
102121
/* A flag that signals completed transfer when threads are
103122
* not enabled.
@@ -214,6 +233,9 @@ static struct qspi_nor_data qspi_nor_memory_data = {
214233
.trans = Z_SEM_INITIALIZER(qspi_nor_memory_data.trans, 1, 1),
215234
.sem = Z_SEM_INITIALIZER(qspi_nor_memory_data.sem, 1, 1),
216235
.sync = Z_SEM_INITIALIZER(qspi_nor_memory_data.sync, 0, 1),
236+
#if NRF52_ERRATA_122_PRESENT
237+
.count = Z_SEM_INITIALIZER(qspi_nor_memory_data.count, 0, K_SEM_MAX_LIMIT),
238+
#endif
217239
#endif /* CONFIG_MULTITHREADING */
218240
};
219241

@@ -332,6 +354,73 @@ static void qspi_handler(nrfx_qspi_evt_t event, void *p_context)
332354
}
333355
}
334356

357+
#if NRF52_ERRATA_122_PRESENT
358+
static bool qspi_initialized;
359+
360+
static int anomaly_122_init(const struct device *dev)
361+
{
362+
struct qspi_nor_data *dev_data = get_dev_data(dev);
363+
nrfx_err_t res;
364+
int ret = 0;
365+
366+
if (!nrf52_errata_122()) {
367+
return 0;
368+
}
369+
370+
qspi_lock(dev);
371+
372+
/* In multithreading, driver can call anomaly_122_init more than once
373+
* before calling anomaly_122_uninit. Keepping count, so QSPI is
374+
* uninitialized only at the last call (count == 0).
375+
*/
376+
#ifdef CONFIG_MULTITHREADING
377+
k_sem_give(&dev_data->count);
378+
#endif
379+
380+
if (!qspi_initialized) {
381+
res = nrfx_qspi_init(&QSPIconfig, qspi_handler, dev_data);
382+
ret = qspi_get_zephyr_ret_code(res);
383+
qspi_initialized = (ret == 0);
384+
}
385+
386+
qspi_unlock(dev);
387+
388+
return ret;
389+
}
390+
391+
static void anomaly_122_uninit(const struct device *dev)
392+
{
393+
struct qspi_nor_data *dev_data = get_dev_data(dev);
394+
bool last = true;
395+
396+
if (!nrf52_errata_122()) {
397+
return;
398+
}
399+
400+
qspi_lock(dev);
401+
402+
#ifdef CONFIG_MULTITHREADING
403+
/* The last thread to finish using the driver uninit the QSPI */
404+
(void) k_sem_take(&dev_data->count, K_NO_WAIT);
405+
last = (k_sem_count_get(&dev_data->count) == 0);
406+
#endif
407+
408+
if (last) {
409+
while (nrfx_qspi_mem_busy_check() != NRFX_SUCCESS) {
410+
k_msleep(50);
411+
}
412+
413+
nrf_gpio_cfg_output(QSPI_PROP_AT(csn_pins, 0));
414+
nrf_gpio_pin_set(QSPI_PROP_AT(csn_pins, 0));
415+
416+
nrfx_qspi_uninit();
417+
qspi_initialized = false;
418+
}
419+
420+
qspi_unlock(dev);
421+
}
422+
#endif /* NRF52_ERRATA_122_PRESENT */
423+
335424

336425
/* QSPI send custom command.
337426
*
@@ -442,6 +531,10 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size)
442531
int rv = 0;
443532
const struct qspi_nor_config *params = dev->config;
444533

534+
rv = ANOMALY_122_INIT(dev);
535+
if (rv != 0) {
536+
goto out;
537+
}
445538
qspi_trans_lock(dev);
446539
rv = qspi_nor_write_protection_set(dev, false);
447540
qspi_lock(dev);
@@ -488,6 +581,8 @@ static int qspi_erase(const struct device *dev, uint32_t addr, uint32_t size)
488581
rv = rv2;
489582
}
490583

584+
out:
585+
ANOMALY_122_UNINIT(dev);
491586
return rv;
492587
}
493588

@@ -555,8 +650,6 @@ static int qspi_nrfx_configure(const struct device *dev)
555650
}
556651

557652
struct qspi_nor_data *dev_data = dev->data;
558-
/* Main config structure */
559-
nrfx_qspi_config_t QSPIconfig;
560653

561654
qspi_fill_init_struct(&QSPIconfig);
562655

@@ -633,7 +726,14 @@ static int qspi_read_jedec_id(const struct device *dev,
633726
.rx_buf = &rx_buf,
634727
};
635728

636-
return qspi_send_cmd(dev, &cmd, false);
729+
int ret = ANOMALY_122_INIT(dev);
730+
731+
if (ret == 0) {
732+
ret = qspi_send_cmd(dev, &cmd, false);
733+
}
734+
ANOMALY_122_UNINIT(dev);
735+
736+
return ret;
637737
}
638738

639739
#if defined(CONFIG_FLASH_JESD216_API)
@@ -656,10 +756,15 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset,
656756
.io3_level = true,
657757
};
658758

659-
qspi_lock(dev);
759+
int res = ANOMALY_122_INIT(dev);
660760

661-
int res = nrfx_qspi_lfm_start(&cinstr_cfg);
761+
if (res != NRFX_SUCCESS) {
762+
LOG_DBG("ANOMALY_122_INIT: %x", res);
763+
goto out;
764+
}
662765

766+
qspi_lock(dev);
767+
res = nrfx_qspi_lfm_start(&cinstr_cfg);
663768
if (res != NRFX_SUCCESS) {
664769
LOG_DBG("lfm_start: %x", res);
665770
goto out;
@@ -679,6 +784,7 @@ static int qspi_sfdp_read(const struct device *dev, off_t offset,
679784

680785
out:
681786
qspi_unlock(dev);
787+
ANOMALY_122_UNINIT(dev);
682788
return qspi_get_zephyr_ret_code(res);
683789
}
684790

@@ -806,14 +912,22 @@ static int qspi_nor_read(const struct device *dev, off_t addr, void *dest,
806912
return -EINVAL;
807913
}
808914

915+
int rc = ANOMALY_122_INIT(dev);
916+
917+
if (rc != 0) {
918+
goto out;
919+
}
920+
809921
qspi_lock(dev);
810922

811923
nrfx_err_t res = read_non_aligned(dev, addr, dest, size);
812924

813925
qspi_unlock(dev);
814926

815-
int rc = qspi_get_zephyr_ret_code(res);
927+
rc = qspi_get_zephyr_ret_code(res);
816928

929+
out:
930+
ANOMALY_122_UNINIT(dev);
817931
return rc;
818932
}
819933

@@ -908,6 +1022,12 @@ static int qspi_nor_write(const struct device *dev, off_t addr,
9081022

9091023
nrfx_err_t res = NRFX_SUCCESS;
9101024

1025+
int rc = ANOMALY_122_INIT(dev);
1026+
1027+
if (rc != 0) {
1028+
goto out;
1029+
}
1030+
9111031
qspi_trans_lock(dev);
9121032
res = qspi_nor_write_protection_set(dev, false);
9131033
qspi_lock(dev);
@@ -930,7 +1050,10 @@ static int qspi_nor_write(const struct device *dev, off_t addr,
9301050
res = res2;
9311051
}
9321052

933-
return qspi_get_zephyr_ret_code(res);
1053+
rc = qspi_get_zephyr_ret_code(res);
1054+
out:
1055+
ANOMALY_122_UNINIT(dev);
1056+
return rc;
9341057
}
9351058

9361059
static int qspi_nor_erase(const struct device *dev, off_t addr, size_t size)
@@ -983,6 +1106,8 @@ static int qspi_nor_configure(const struct device *dev)
9831106
return ret;
9841107
}
9851108

1109+
ANOMALY_122_UNINIT(dev);
1110+
9861111
/* now the spi bus is configured, we can verify the flash id */
9871112
if (qspi_nor_read_id(dev, params) != 0) {
9881113
return -ENODEV;

0 commit comments

Comments
 (0)