1 /*
2 * Copyright 2024 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * Based on memc_mcux_flexspi_s27ks0641, which is: Copyright 2021 Basalte bv
9 */
10
11 #define DT_DRV_COMPAT nxp_imx_flexspi_aps6404l
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/sys/util.h>
16
17 #include "memc_mcux_flexspi.h"
18
19
20 /*
21 * NOTE: If CONFIG_FLASH_MCUX_FLEXSPI_XIP is selected, Any external functions
22 * called while interacting with the flexspi MUST be relocated to SRAM or ITCM
23 * at runtime, so that the chip does not access the flexspi to read program
24 * instructions while it is being written to
25 */
26 #if defined(CONFIG_FLASH_MCUX_FLEXSPI_XIP) && (CONFIG_MEMC_LOG_LEVEL > 0)
27 #warning "Enabling memc driver logging and XIP mode simultaneously can cause \
28 read-while-write hazards. This configuration is not recommended."
29 #endif
30
31 LOG_MODULE_REGISTER(memc_flexspi_aps6404l, CONFIG_MEMC_LOG_LEVEL);
32
33 #define APM_VENDOR_ID 0xD
34
35 enum {
36 READ_DATA = 0,
37 WRITE_DATA,
38 RESET_EN,
39 RESET,
40 READ_ID
41 };
42
43 struct memc_flexspi_aps6404l_config {
44 flexspi_port_t port;
45 flexspi_device_config_t config;
46 };
47
48 /* Device variables used in critical sections should be in this structure */
49 struct memc_flexspi_aps6404l_data {
50 const struct device *controller;
51 };
52
53
54 static const uint32_t memc_flexspi_aps6404l_lut[][4] = {
55 /* Read Data (Sync read, linear burst) */
56 [READ_DATA] = {
57 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xEB,
58 kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x18),
59 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD,
60 0x06, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04),
61 },
62 /* Write Data (Sync write, linear burst) */
63 [WRITE_DATA] = {
64 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x38,
65 kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x18),
66 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD,
67 0x00, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
68 },
69
70 [RESET_EN] = {
71 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x66,
72 kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
73 },
74 /* Reset (Global reset) */
75 [RESET] = {
76 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x99,
77 kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
78 },
79
80 [READ_ID] = {
81 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x9F,
82 kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
83 FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x08,
84 kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
85 },
86 };
87
88
memc_flexspi_aps6404l_get_vendor_id(const struct device * dev,uint8_t * vendor_id)89 static int memc_flexspi_aps6404l_get_vendor_id(const struct device *dev,
90 uint8_t *vendor_id)
91 {
92 const struct memc_flexspi_aps6404l_config *config = dev->config;
93 struct memc_flexspi_aps6404l_data *data = dev->data;
94 uint32_t buffer = 0;
95 int ret;
96
97 flexspi_transfer_t transfer = {
98 .deviceAddress = 0x0,
99 .port = config->port,
100 .cmdType = kFLEXSPI_Read,
101 .SeqNumber = 1,
102 .seqIndex = READ_ID,
103 .data = &buffer,
104 .dataSize = 1,
105 };
106
107 ret = memc_flexspi_transfer(data->controller, &transfer);
108 *vendor_id = buffer & 0x1f;
109
110 return ret;
111 }
112
memc_flexspi_aps6404l_reset_enable(const struct device * dev)113 static int memc_flexspi_aps6404l_reset_enable(const struct device *dev)
114 {
115 const struct memc_flexspi_aps6404l_config *config = dev->config;
116 struct memc_flexspi_aps6404l_data *data = dev->data;
117 int ret;
118
119 flexspi_transfer_t transfer = {
120 .deviceAddress = 0x0,
121 .port = config->port,
122 .cmdType = kFLEXSPI_Command,
123 .SeqNumber = 1,
124 .seqIndex = RESET_EN,
125 .data = NULL,
126 .dataSize = 0,
127 };
128
129 LOG_DBG("Enabling reset ram");
130 ret = memc_flexspi_transfer(data->controller, &transfer);
131 if (ret < 0) {
132 return ret;
133 }
134 /* We need to delay 5 ms to allow APS6404L pSRAM to reinitialize */
135 k_msleep(5);
136
137 return ret;
138 }
139
140
memc_flexspi_aps6404l_reset(const struct device * dev)141 static int memc_flexspi_aps6404l_reset(const struct device *dev)
142 {
143 const struct memc_flexspi_aps6404l_config *config = dev->config;
144 struct memc_flexspi_aps6404l_data *data = dev->data;
145 int ret;
146
147 flexspi_transfer_t transfer = {
148 .deviceAddress = 0x0,
149 .port = config->port,
150 .cmdType = kFLEXSPI_Command,
151 .SeqNumber = 1,
152 .seqIndex = RESET,
153 .data = NULL,
154 .dataSize = 0,
155 };
156
157 LOG_DBG("Resetting ram");
158 ret = memc_flexspi_transfer(data->controller, &transfer);
159 if (ret < 0) {
160 return ret;
161 }
162 /* We need to delay 5 ms to allow APS6404L pSRAM to reinitialize */
163 k_msleep(5);
164
165 return ret;
166 }
167
memc_flexspi_aps6404l_init(const struct device * dev)168 static int memc_flexspi_aps6404l_init(const struct device *dev)
169 {
170 const struct memc_flexspi_aps6404l_config *config = dev->config;
171 struct memc_flexspi_aps6404l_data *data = dev->data;
172 uint8_t vendor_id;
173
174 if (!device_is_ready(data->controller)) {
175 LOG_ERR("Controller device not ready");
176 return -ENODEV;
177 }
178
179 if (memc_flexspi_set_device_config(data->controller, &config->config,
180 (const uint32_t *) memc_flexspi_aps6404l_lut,
181 sizeof(memc_flexspi_aps6404l_lut) / MEMC_FLEXSPI_CMD_SIZE,
182 config->port)) {
183 LOG_ERR("Could not set device configuration");
184 return -EINVAL;
185 }
186
187 memc_flexspi_reset(data->controller);
188
189 if (memc_flexspi_aps6404l_reset_enable(dev)) {
190 LOG_ERR("Could not enable reset pSRAM");
191 return -EIO;
192 }
193
194 if (memc_flexspi_aps6404l_reset(dev)) {
195 LOG_ERR("Could not reset pSRAM");
196 return -EIO;
197 }
198
199 if (memc_flexspi_aps6404l_get_vendor_id(dev, &vendor_id)) {
200 LOG_ERR("Could not read vendor id");
201 return -EIO;
202 }
203 LOG_DBG("Vendor id: 0x%0x", vendor_id);
204 if (vendor_id != APM_VENDOR_ID) {
205 LOG_WRN("Vendor ID does not match expected value of 0x%0x",
206 APM_VENDOR_ID);
207 }
208
209 return 0;
210 }
211
212 #define CONCAT3(x, y, z) x ## y ## z
213
214 #define CS_INTERVAL_UNIT(unit) \
215 CONCAT3(kFLEXSPI_CsIntervalUnit, unit, SckCycle)
216
217 #define AHB_WRITE_WAIT_UNIT(unit) \
218 CONCAT3(kFLEXSPI_AhbWriteWaitUnit, unit, AhbCycle)
219
220 #define MEMC_FLEXSPI_DEVICE_CONFIG(n) \
221 { \
222 .flexspiRootClk = DT_INST_PROP(n, spi_max_frequency), \
223 .isSck2Enabled = false, \
224 .flashSize = DT_INST_PROP(n, size) / 8 / KB(1), \
225 .addressShift = false, \
226 .CSIntervalUnit = \
227 CS_INTERVAL_UNIT( \
228 DT_INST_PROP(n, cs_interval_unit)), \
229 .CSInterval = DT_INST_PROP(n, cs_interval), \
230 .CSHoldTime = DT_INST_PROP(n, cs_hold_time), \
231 .CSSetupTime = DT_INST_PROP(n, cs_setup_time), \
232 .dataValidTime = DT_INST_PROP(n, data_valid_time), \
233 .columnspace = DT_INST_PROP(n, column_space), \
234 .enableWordAddress = DT_INST_PROP(n, word_addressable), \
235 .AWRSeqIndex = WRITE_DATA, \
236 .AWRSeqNumber = 1, \
237 .ARDSeqIndex = READ_DATA, \
238 .ARDSeqNumber = 1, \
239 .AHBWriteWaitUnit = \
240 AHB_WRITE_WAIT_UNIT( \
241 DT_INST_PROP(n, ahb_write_wait_unit)), \
242 .AHBWriteWaitInterval = \
243 DT_INST_PROP(n, ahb_write_wait_interval), \
244 .enableWriteMask = false, \
245 } \
246
247 #define MEMC_FLEXSPI_APS6404L(n) \
248 static const struct memc_flexspi_aps6404l_config \
249 memc_flexspi_aps6404l_config_##n = { \
250 .port = DT_INST_REG_ADDR(n), \
251 .config = MEMC_FLEXSPI_DEVICE_CONFIG(n), \
252 }; \
253 \
254 static struct memc_flexspi_aps6404l_data \
255 memc_flexspi_aps6404l_data_##n = { \
256 .controller = DEVICE_DT_GET(DT_INST_BUS(n)), \
257 }; \
258 \
259 DEVICE_DT_INST_DEFINE(n, \
260 memc_flexspi_aps6404l_init, \
261 NULL, \
262 &memc_flexspi_aps6404l_data_##n, \
263 &memc_flexspi_aps6404l_config_##n, \
264 POST_KERNEL, \
265 CONFIG_MEMC_INIT_PRIORITY, \
266 NULL);
267
268 DT_INST_FOREACH_STATUS_OKAY(MEMC_FLEXSPI_APS6404L)
269