Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | /* * Copyright (c) 2016 Linaro Limited * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT openisa_rv32m1_ftfe #define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) #include <kernel.h> #include <device.h> #include <string.h> #include <drivers/flash.h> #include <errno.h> #include <init.h> #include <soc.h> #include "flash_priv.h" #include "fsl_common.h" #include "fsl_flash.h" struct flash_priv { flash_config_t config; /* * HACK: flash write protection is managed in software. */ struct k_sem write_lock; uint32_t pflash_block_base; }; static const struct flash_parameters flash_mcux_parameters = { .write_block_size = FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE, .erase_value = 0xff, }; /* * Interrupt vectors could be executed from flash hence the need for locking. * The underlying MCUX driver takes care of copying the functions to SRAM. * * For more information, see the application note below on Read-While-Write * http://cache.freescale.com/files/32bit/doc/app_note/AN4695.pdf * */ static int flash_mcux_erase(const struct device *dev, off_t offset, size_t len) { struct flash_priv *priv = dev->data; uint32_t addr; status_t rc; unsigned int key; if (k_sem_take(&priv->write_lock, K_NO_WAIT)) { return -EACCES; } addr = offset + priv->pflash_block_base; key = irq_lock(); rc = FLASH_Erase(&priv->config, addr, len, kFLASH_ApiEraseKey); irq_unlock(key); k_sem_give(&priv->write_lock); return (rc == kStatus_Success) ? 0 : -EINVAL; } static int flash_mcux_read(const struct device *dev, off_t offset, void *data, size_t len) { struct flash_priv *priv = dev->data; uint32_t addr; /* * The MCUX supports different flash chips whose valid ranges are * hidden below the API: until the API export these ranges, we can not * do any generic validation */ addr = offset + priv->pflash_block_base; memcpy(data, (void *) addr, len); return 0; } static int flash_mcux_write(const struct device *dev, off_t offset, const void *data, size_t len) { struct flash_priv *priv = dev->data; uint32_t addr; status_t rc; unsigned int key; if (k_sem_take(&priv->write_lock, K_NO_WAIT)) { return -EACCES; } addr = offset + priv->pflash_block_base; key = irq_lock(); rc = FLASH_Program(&priv->config, addr, (uint32_t *) data, len); irq_unlock(key); k_sem_give(&priv->write_lock); return (rc == kStatus_Success) ? 0 : -EINVAL; } static int flash_mcux_write_protection(const struct device *dev, bool enable) { struct flash_priv *priv = dev->data; int rc = 0; if (enable) { rc = k_sem_take(&priv->write_lock, K_FOREVER); } else { k_sem_give(&priv->write_lock); } return rc; } #if defined(CONFIG_FLASH_PAGE_LAYOUT) static const struct flash_pages_layout dev_layout = { .pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) / DT_PROP(SOC_NV_FLASH_NODE, erase_block_size), .pages_size = DT_PROP(SOC_NV_FLASH_NODE, erase_block_size), }; static void flash_mcux_pages_layout(const struct device *dev, const struct flash_pages_layout **layout, size_t *layout_size) { *layout = &dev_layout; *layout_size = 1; } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ static const struct flash_parameters * flash_mcux_get_parameters(const struct device *dev) { ARG_UNUSED(dev); return &flash_mcux_parameters; } static struct flash_priv flash_data; static const struct flash_driver_api flash_mcux_api = { .write_protection = flash_mcux_write_protection, .erase = flash_mcux_erase, .write = flash_mcux_write, .read = flash_mcux_read, .get_parameters = flash_mcux_get_parameters, #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = flash_mcux_pages_layout, #endif }; static int flash_mcux_init(const struct device *dev) { struct flash_priv *priv = dev->data; uint32_t pflash_block_base; status_t rc; CLOCK_EnableClock(kCLOCK_Mscm); k_sem_init(&priv->write_lock, 0, 1); rc = FLASH_Init(&priv->config); FLASH_GetProperty(&priv->config, kFLASH_PropertyPflashBlockBaseAddr, (uint32_t *)&pflash_block_base); priv->pflash_block_base = (uint32_t) pflash_block_base; return (rc == kStatus_Success) ? 0 : -EIO; } DEVICE_AND_API_INIT(flash_mcux, DT_INST_LABEL(0), flash_mcux_init, &flash_data, NULL, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &flash_mcux_api); |