Skip to content

Commit

Permalink
drivers/flash/mcux: fix flash_read() operation on LPC55S36
Browse files Browse the repository at this point in the history
As other targets in the LPC55xxx series, the LPC55S36 has a Flash
controller that raises ECC errors when reading erased pages directly.
To avoid this, there is special code for this platform that calls the
HAL FLASH_IsFlashAreaReadable() function. However, this in turn calls a
function at an hardcoded address in ROM that _always_ causes an
instruction fault, making the situation worse.

This patch reworks the read operation to use the FLASH_Read() HAL
function for this target to gracefully handle error conditions and
properly emulate accesses to erased pages. The preprocessor is required
since some targets do not define the FLASH_Read() function.

Fixes: #80325

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
  • Loading branch information
pillo79 authored and mmahadevan108 committed Nov 7, 2024
1 parent 5a03d3f commit 20cd3a3
Showing 1 changed file with 33 additions and 15 deletions.
48 changes: 33 additions & 15 deletions drivers/flash/soc_flash_mcux.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ LOG_MODULE_REGISTER(flash_mcux);

#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash)

#if defined(CONFIG_CHECK_BEFORE_READING) && !defined(CONFIG_SOC_LPC55S36)
#if defined(CONFIG_CHECK_BEFORE_READING) && !defined(CONFIG_SOC_LPC55S36)
#define FMC_STATUS_FAIL FLASH_INT_CLR_ENABLE_FAIL_MASK
#define FMC_STATUS_ERR FLASH_INT_CLR_ENABLE_ERR_MASK
#define FMC_STATUS_DONE FLASH_INT_CLR_ENABLE_DONE_MASK
Expand Down Expand Up @@ -205,35 +205,53 @@ static int flash_mcux_read(const struct device *dev, off_t offset,
addr = offset + priv->pflash_block_base;

#ifdef CONFIG_CHECK_BEFORE_READING
/*
* Ensure the area is readable, since a direct access may cause faults
* on erased or otherwise unreadable pages. Emulate erased pages,
* return other errors.
*/
#ifdef CONFIG_SOC_LPC55S36
/* Validates the given address range is loaded in the flash hiding region. */
rc = FLASH_IsFlashAreaReadable(&priv->config, addr, len);
if (rc != kStatus_FLASH_Success) {
rc = -EIO;
} else {
/* Check whether the flash is erased ("len" and "addr" must be word-aligned). */
/* On LPC55S36, use a HAL function to safely copy from Flash. */
rc = FLASH_Read(&priv->config, addr, data, len);
switch (rc) {
case kStatus_FLASH_Success:
rc = 0;
break;
case kStatus_FLASH_EccError:
/* Check id the ECC issue is due to the Flash being erased
* ("addr" and "len" must be word-aligned for this call).
*/
rc = FLASH_VerifyErase(&priv->config, ((addr + 0x3) & ~0x3), ((len + 0x3) & ~0x3));
if (rc == kStatus_FLASH_Success) {
rc = -ENODATA;
} else {
rc = 0;
rc = -EIO;
}
break;
default:
rc = -EIO;
break;
}
#else
#else /* CONFIG_SOC_LPC55S36 */
/* On all other targets, check if the Flash area is readable.
* If so, copy data from it directly.
*/
rc = is_area_readable(addr, len);
#endif /* CONFIG_SOC_LPC55S36 */
#endif /* CONFIG_CHECK_BEFORE_READING */

if (!rc) {
memcpy(data, (void *) addr, len);
}
#ifdef CONFIG_CHECK_BEFORE_READING
else if (rc == -ENODATA) {
#endif /* CONFIG_SOC_LPC55S36 */

if (rc == -ENODATA) {
/* Erased area, return dummy data as an erased page. */
memset(data, 0xFF, len);
rc = 0;
}
#endif
#else /* CONFIG_CHECK_BEFORE_READING */
/* No safety checks, directly copy the memory mapped data. */
memcpy(data, (void *) addr, len);
#endif /* CONFIG_CHECK_BEFORE_READING */

return rc;
}

Expand Down

0 comments on commit 20cd3a3

Please sign in to comment.