Skip to content

Commit 2d9ede3

Browse files
ananglkartben
authored andcommitted
drivers: flash: nrf_qspi_nor: Handle properly multiple XIP users
Add reference counting in nrf_qspi_nor_xip_enable() so that XIP is kept enabled as long as there is at least one user that needs it (boot time enabling done with CONFIG_NORDIC_QSPI_NOR_XIP also counts). Signed-off-by: Andrzej Głąbek <andrzej.glabek@nordicsemi.no>
1 parent dfb5a31 commit 2d9ede3

File tree

1 file changed

+42
-23
lines changed

1 file changed

+42
-23
lines changed

drivers/flash/nrf_qspi_nor.c

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ struct qspi_nor_data {
4141
*/
4242
volatile bool ready;
4343
#endif /* CONFIG_MULTITHREADING */
44-
bool xip_enabled;
44+
uint32_t xip_users;
4545
};
4646

4747
struct qspi_nor_config {
@@ -313,7 +313,7 @@ static void qspi_acquire(const struct device *dev)
313313

314314
qspi_lock(dev);
315315

316-
if (!dev_data->xip_enabled) {
316+
if (dev_data->xip_users == 0) {
317317
qspi_clock_div_change();
318318

319319
pm_device_busy_set(dev);
@@ -331,7 +331,7 @@ static void qspi_release(const struct device *dev)
331331
deactivate = atomic_dec(&dev_data->usage_count) == 1;
332332
#endif
333333

334-
if (!dev_data->xip_enabled) {
334+
if (dev_data->xip_users == 0) {
335335
qspi_clock_div_restore();
336336

337337
if (deactivate) {
@@ -1344,35 +1344,54 @@ static int qspi_nor_pm_action(const struct device *dev,
13441344
}
13451345
#endif /* CONFIG_PM_DEVICE */
13461346

1347+
static void on_xip_enable(const struct device *dev)
1348+
{
1349+
#if NRF_QSPI_HAS_XIPEN
1350+
nrf_qspi_xip_set(NRF_QSPI, true);
1351+
#endif
1352+
(void)nrfx_qspi_activate(false);
1353+
}
1354+
1355+
static void on_xip_disable(const struct device *dev)
1356+
{
1357+
/* It turns out that when the QSPI peripheral is deactivated
1358+
* after a XIP transaction, it cannot be later successfully
1359+
* reactivated and an attempt to perform another XIP transaction
1360+
* results in the CPU being hung; even a debug session cannot be
1361+
* started then and the SoC has to be recovered.
1362+
* As a workaround, at least until the cause of such behavior
1363+
* is fully clarified, perform a simple non-XIP transaction
1364+
* (a read of the status register) before deactivating the QSPI.
1365+
* This prevents the issue from occurring.
1366+
*/
1367+
(void)qspi_rdsr(dev, 1);
1368+
1369+
#if NRF_QSPI_HAS_XIPEN
1370+
nrf_qspi_xip_set(NRF_QSPI, false);
1371+
#endif
1372+
}
1373+
13471374
void z_impl_nrf_qspi_nor_xip_enable(const struct device *dev, bool enable)
13481375
{
13491376
struct qspi_nor_data *dev_data = dev->data;
13501377

1351-
if (dev_data->xip_enabled == enable) {
1352-
return;
1353-
}
1354-
13551378
qspi_acquire(dev);
13561379

1357-
#if NRF_QSPI_HAS_XIPEN
1358-
nrf_qspi_xip_set(NRF_QSPI, enable);
1359-
#endif
13601380
if (enable) {
1361-
(void)nrfx_qspi_activate(false);
1381+
if (dev_data->xip_users == 0) {
1382+
on_xip_enable(dev);
1383+
}
1384+
1385+
++dev_data->xip_users;
1386+
} else if (dev_data->xip_users == 0) {
1387+
LOG_ERR("Unbalanced XIP disabling");
13621388
} else {
1363-
/* It turns out that when the QSPI peripheral is deactivated
1364-
* after a XIP transaction, it cannot be later successfully
1365-
* reactivated and an attempt to perform another XIP transaction
1366-
* results in the CPU being hung; even a debug session cannot be
1367-
* started then and the SoC has to be recovered.
1368-
* As a workaround, at least until the cause of such behavior
1369-
* is fully clarified, perform a simple non-XIP transaction
1370-
* (a read of the status register) before deactivating the QSPI.
1371-
* This prevents the issue from occurring.
1372-
*/
1373-
(void)qspi_rdsr(dev, 1);
1389+
--dev_data->xip_users;
1390+
1391+
if (dev_data->xip_users == 0) {
1392+
on_xip_disable(dev);
1393+
}
13741394
}
1375-
dev_data->xip_enabled = enable;
13761395

13771396
qspi_release(dev);
13781397
}

0 commit comments

Comments
 (0)