blob: 5f931a1bf73482bf7c6f4ecbd8508f608c27fecb [file] [log] [blame]
Andrei Gansari6587c932020-07-02 14:58:31 +03001/*
2 * Copyright (c) 2020 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
Gerard Marull-Paretasfb60aab2022-05-06 10:25:46 +02007#include <zephyr/kernel.h>
8#include <zephyr/device.h>
Andrei Gansari6587c932020-07-02 14:58:31 +03009#include <string.h>
Gerard Marull-Paretasfb60aab2022-05-06 10:25:46 +020010#include <zephyr/drivers/flash.h>
Andrei Gansari6587c932020-07-02 14:58:31 +030011#include <errno.h>
Gerard Marull-Paretasfb60aab2022-05-06 10:25:46 +020012#include <zephyr/init.h>
Andrei Gansari6587c932020-07-02 14:58:31 +030013#include <soc.h>
14#include "flash_priv.h"
15
16#include "fsl_common.h"
17#include "fsl_flashiap.h"
18
19
Yong Cong Sin52a20232024-09-20 12:47:40 +080020#if DT_NODE_HAS_STATUS_OKAY(DT_INST(0, nxp_iap_fmc11))
Yves Vandervennetda3d0b32022-08-12 09:05:25 -050021#define DT_DRV_COMPAT nxp_iap_fmc11
Yong Cong Sin52a20232024-09-20 12:47:40 +080022#elif DT_NODE_HAS_STATUS_OKAY(DT_INST(0, nxp_iap_fmc54))
Daniel DeGrassed70db212022-08-18 13:13:54 -050023#define DT_DRV_COMPAT nxp_iap_fmc54
Andrei Gansari6587c932020-07-02 14:58:31 +030024#else
25#error No matching compatible for soc_flash_lpc.c
26#endif
27
28#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash)
29
30struct flash_priv {
31 /* HACK: flash write protection is managed in software. */
32 struct k_sem write_lock;
33 uint32_t pflash_block_base;
34 uint32_t sector_size;
35};
36
37static const struct flash_parameters flash_lpc_parameters = {
38#if DT_NODE_HAS_PROP(SOC_NV_FLASH_NODE, write_block_size)
39 .write_block_size = DT_PROP(SOC_NV_FLASH_NODE, write_block_size),
40#else
41 .write_block_size = FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE,
42#endif
43 .erase_value = 0xff,
44};
45
46static inline void prepare_erase_write(off_t offset, size_t len,
47 uint32_t sector_size)
48{
49 uint32_t start;
50 uint32_t stop;
51
52 start = offset / sector_size;
53 stop = (offset+len-1) / sector_size;
54 FLASHIAP_PrepareSectorForWrite(start, stop);
55}
56
57static int flash_lpc_erase(const struct device *dev, off_t offset, size_t len)
58{
59 struct flash_priv *priv = dev->data;
60 status_t rc;
61 unsigned int key;
62 uint32_t start;
63 uint32_t stop;
64 uint32_t page_size;
65
Andrzej Puzdrowski8e3eb3c2021-03-12 11:01:31 +010066 if (k_sem_take(&priv->write_lock, K_FOREVER)) {
Andrei Gansari6587c932020-07-02 14:58:31 +030067 return -EACCES;
68 }
69
70 key = irq_lock();
71 prepare_erase_write(offset, len, priv->sector_size);
72 page_size = flash_lpc_parameters.write_block_size;
73 start = offset / page_size;
74 stop = (offset+len-1) / page_size;
75 rc = FLASHIAP_ErasePage(start, stop,
76 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC);
77 irq_unlock(key);
78
79 k_sem_give(&priv->write_lock);
80
81 return (rc == kStatus_FLASHIAP_Success) ? 0 : -EINVAL;
82}
83
84static int flash_lpc_read(const struct device *dev, off_t offset,
85 void *data, size_t len)
86{
87 struct flash_priv *priv = dev->data;
88 uint32_t addr;
89
90 addr = offset + priv->pflash_block_base;
91
92 memcpy(data, (void *) addr, len);
93
94 return 0;
95}
96
97static int flash_lpc_write(const struct device *dev, off_t offset,
98 const void *data, size_t len)
99{
100 struct flash_priv *priv = dev->data;
101 uint32_t addr;
102 status_t rc;
103 unsigned int key;
104
Andrzej Puzdrowski8e3eb3c2021-03-12 11:01:31 +0100105 if (k_sem_take(&priv->write_lock, K_FOREVER)) {
Andrei Gansari6587c932020-07-02 14:58:31 +0300106 return -EACCES;
107 }
108
109 addr = offset + priv->pflash_block_base;
110
111 key = irq_lock();
112 prepare_erase_write(offset, len, priv->sector_size);
113 rc = FLASHIAP_CopyRamToFlash(addr, (uint32_t *) data, len,
114 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC);
115 irq_unlock(key);
116
117 k_sem_give(&priv->write_lock);
118
119 return (rc == kStatus_FLASHIAP_Success) ? 0 : -EINVAL;
120}
121
Andrei Gansari6587c932020-07-02 14:58:31 +0300122#if defined(CONFIG_FLASH_PAGE_LAYOUT)
123static const struct flash_pages_layout dev_layout = {
124 .pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) /
125 DT_PROP(SOC_NV_FLASH_NODE, erase_block_size),
126 .pages_size = DT_PROP(SOC_NV_FLASH_NODE, erase_block_size),
127};
128
129static void flash_lpc_pages_layout(const struct device *dev,
130 const struct flash_pages_layout **layout,
131 size_t *layout_size)
132{
133 *layout = &dev_layout;
134 *layout_size = 1;
135}
136#endif /* CONFIG_FLASH_PAGE_LAYOUT */
137
138static const struct flash_parameters *
139flash_lpc_get_parameters(const struct device *dev)
140{
141 ARG_UNUSED(dev);
142
143 return &flash_lpc_parameters;
144}
145
146static struct flash_priv flash_data;
147
148static const struct flash_driver_api flash_lpc_api = {
Andrei Gansari6587c932020-07-02 14:58:31 +0300149 .erase = flash_lpc_erase,
150 .write = flash_lpc_write,
151 .read = flash_lpc_read,
152 .get_parameters = flash_lpc_get_parameters,
153#if defined(CONFIG_FLASH_PAGE_LAYOUT)
154 .page_layout = flash_lpc_pages_layout,
155#endif
156};
157
158static int flash_lpc_init(const struct device *dev)
159{
160 struct flash_priv *priv = dev->data;
161
Andrzej Puzdrowski8e3eb3c2021-03-12 11:01:31 +0100162 k_sem_init(&priv->write_lock, 1, 1);
Andrei Gansari6587c932020-07-02 14:58:31 +0300163
164 priv->pflash_block_base = DT_REG_ADDR(SOC_NV_FLASH_NODE);
165
166#if defined(FSL_FEATURE_SYSCON_FLASH_SECTOR_SIZE_BYTES)
167 priv->sector_size = FSL_FEATURE_SYSCON_FLASH_SECTOR_SIZE_BYTES;
168#else
169 #error "Sector size not set"
170#endif
171
172 return 0;
173}
174
Gerard Marull-Paretasfaeaea12021-04-28 10:46:57 +0200175DEVICE_DT_INST_DEFINE(0, flash_lpc_init, NULL,
Andrei Gansari6587c932020-07-02 14:58:31 +0300176 &flash_data, NULL, POST_KERNEL,
Maureen Helme0cb96c2021-12-01 13:13:02 -0600177 CONFIG_FLASH_INIT_PRIORITY, &flash_lpc_api);