1 /*
2  * Copyright (c) 2020 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <string.h>
10 #include <zephyr/drivers/flash.h>
11 #include <errno.h>
12 #include <zephyr/init.h>
13 #include <soc.h>
14 #include "flash_priv.h"
15 
16 #include "fsl_common.h"
17 #include "fsl_flashiap.h"
18 
19 
20 #if DT_NODE_HAS_STATUS(DT_INST(0, nxp_iap_fmc11), okay)
21 #define DT_DRV_COMPAT nxp_iap_fmc11
22 #elif DT_NODE_HAS_STATUS(DT_INST(0, nxp_iap_fmc54), okay)
23 #define DT_DRV_COMPAT nxp_iap_fmc54
24 #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 
30 struct 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 
37 static 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 
prepare_erase_write(off_t offset,size_t len,uint32_t sector_size)46 static 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 
flash_lpc_erase(const struct device * dev,off_t offset,size_t len)57 static 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 
66 	if (k_sem_take(&priv->write_lock, K_FOREVER)) {
67 		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 
flash_lpc_read(const struct device * dev,off_t offset,void * data,size_t len)84 static 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 
flash_lpc_write(const struct device * dev,off_t offset,const void * data,size_t len)97 static 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 
105 	if (k_sem_take(&priv->write_lock, K_FOREVER)) {
106 		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 
122 #if defined(CONFIG_FLASH_PAGE_LAYOUT)
123 static 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 
flash_lpc_pages_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)129 static 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 
138 static const struct flash_parameters *
flash_lpc_get_parameters(const struct device * dev)139 flash_lpc_get_parameters(const struct device *dev)
140 {
141 	ARG_UNUSED(dev);
142 
143 	return &flash_lpc_parameters;
144 }
145 
146 static struct flash_priv flash_data;
147 
148 static const struct flash_driver_api flash_lpc_api = {
149 	.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 
flash_lpc_init(const struct device * dev)158 static int flash_lpc_init(const struct device *dev)
159 {
160 	struct flash_priv *priv = dev->data;
161 
162 	k_sem_init(&priv->write_lock, 1, 1);
163 
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 
175 DEVICE_DT_INST_DEFINE(0, flash_lpc_init, NULL,
176 			&flash_data, NULL, POST_KERNEL,
177 			CONFIG_FLASH_INIT_PRIORITY, &flash_lpc_api);
178