Skip to content

Commit 64a14a8

Browse files
danieldegrassecarlescufi
authored andcommitted
drivers: memc: introduce driver for APS6408L PSRAM
Introduce driver for APS6408L PSRAM, built on top of the MCUX memc driver for flexSPI. This driver supports operating the PSRAM in high speed mode (200MHz or more). Note that in order to support this PSRAM's alignment requirements, either ahb-read-addr-opt or ahb-prefetch must be set for the FlexSPI instance. Signed-off-by: Daniel DeGrasse <[email protected]>
1 parent 41acdc1 commit 64a14a8

File tree

4 files changed

+344
-0
lines changed

4 files changed

+344
-0
lines changed

drivers/memc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ zephyr_library_sources_ifdef(CONFIG_MEMC_STM32_NOR_PSRAM memc_stm32_nor_psram.c)
99

1010
zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI memc_mcux_flexspi.c)
1111
zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_S27KS0641 memc_mcux_flexspi_s27ks0641.c)
12+
zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_APS6408L memc_mcux_flexspi_aps6408l.c)
1213

1314
zephyr_library_sources_ifdef(CONFIG_MEMC_SAM_SMC memc_sam_smc.c)
1415

drivers/memc/Kconfig.mcux

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ config MEMC_MCUX_FLEXSPI_S27KS0641
1010
depends on DT_HAS_NXP_IMX_FLEXSPI_S27KS0641_ENABLED
1111
select MEMC_MCUX_FLEXSPI
1212

13+
config MEMC_MCUX_FLEXSPI_APS6408L
14+
bool "MCUX FlexSPI AP Memory APS6408L pSRAM driver"
15+
default y
16+
depends on DT_HAS_NXP_IMX_FLEXSPI_APS6408L_ENABLED
17+
select MEMC_MCUX_FLEXSPI
18+
1319
config MEMC_MCUX_FLEXSPI
1420
bool
1521

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
/*
2+
* Copyright 2022 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_aps6408l
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_aps6408l, CONFIG_MEMC_LOG_LEVEL);
32+
33+
#define APM_VENDOR_ID 0xD
34+
35+
/* APS6408L Configuration registers */
36+
#define APS_6408L_MR_0 0x0
37+
#define APS_6408L_MR_1 0x1
38+
#define APS_6408L_MR_2 0x2
39+
#define APS_6408L_MR_3 0x3
40+
#define APS_6408L_MR_4 0x4
41+
#define APS_6408L_MR_6 0x6
42+
#define APS_6408L_MR_8 0x8
43+
44+
45+
/* Read Latency code (MR0[4:2]) */
46+
#define APS_6408L_RLC_MASK 0x1C
47+
#define APS_6408L_RLC_200 0x10 /* 200MHz input clock read latency */
48+
/* Read Latency type (MR0[5]) */
49+
#define APS_6408L_RLT_MASK 0x30
50+
#define APS_6408L_RLT_VARIABLE 0x0 /* Variable latency */
51+
52+
/* Burst type/burst length mask (MR8[0:2]) */
53+
#define APS_6408L_BURST_TYPE_MASK 0x7
54+
#define APS_6408L_BURST_1K 0x7 /* 1K Hybrid wrap */
55+
/* Row boundary cross enable mask (MR8[3]) */
56+
#define APS_6408L_ROW_CROSS_MASK 0x8
57+
#define APS_6408L_ROW_CROSS_EN 0x8 /* Enable linear burst reads to cross rows */
58+
59+
/* Write latency (MR4[7:5]) */
60+
#define APS_6408L_WLC_MASK 0xE0
61+
#define APS_6408L_WLC_200 0x20 /* 200MHz input clock write latency */
62+
63+
64+
enum {
65+
READ_DATA = 0,
66+
WRITE_DATA,
67+
READ_REG,
68+
WRITE_REG,
69+
RESET,
70+
};
71+
72+
struct memc_flexspi_aps6408l_config {
73+
flexspi_port_t port;
74+
flexspi_device_config_t config;
75+
};
76+
77+
/* Device variables used in critical sections should be in this structure */
78+
struct memc_flexspi_aps6408l_data {
79+
const struct device *controller;
80+
};
81+
82+
83+
static const uint32_t memc_flexspi_aps6408l_lut[][4] = {
84+
/* Read Data (Sync read, linear burst) */
85+
[READ_DATA] = {
86+
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0x20,
87+
kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x20),
88+
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD,
89+
0x07, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
90+
},
91+
/* Write Data (Sync write, linear burst) */
92+
[WRITE_DATA] = {
93+
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0xA0,
94+
kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x20),
95+
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD,
96+
0x07, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x04),
97+
},
98+
/* Read Register (Mode register read) */
99+
[READ_REG] = {
100+
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0x40,
101+
kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x20),
102+
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD,
103+
0x07, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04),
104+
},
105+
/* Write Register (Mode register write) */
106+
[WRITE_REG] = {
107+
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0xC0,
108+
kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x20),
109+
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x08,
110+
kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
111+
},
112+
/* Reset (Global reset) */
113+
[RESET] = {
114+
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0xFF,
115+
kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_8PAD, 0x03),
116+
}
117+
};
118+
119+
120+
static int memc_flexspi_aps6408l_get_vendor_id(const struct device *dev,
121+
uint8_t *vendor_id)
122+
{
123+
const struct memc_flexspi_aps6408l_config *config = dev->config;
124+
struct memc_flexspi_aps6408l_data *data = dev->data;
125+
uint32_t buffer = 0;
126+
int ret;
127+
128+
flexspi_transfer_t transfer = {
129+
.deviceAddress = APS_6408L_MR_1,
130+
.port = config->port,
131+
.cmdType = kFLEXSPI_Read,
132+
.SeqNumber = 1,
133+
.seqIndex = READ_REG,
134+
.data = &buffer,
135+
.dataSize = 1,
136+
};
137+
138+
ret = memc_flexspi_transfer(data->controller, &transfer);
139+
*vendor_id = buffer & 0x1f;
140+
141+
return ret;
142+
}
143+
144+
static int memc_flexspi_aps6408l_update_reg(const struct device *dev,
145+
uint8_t reg, uint8_t mask, uint8_t set_val)
146+
{
147+
const struct memc_flexspi_aps6408l_config *config = dev->config;
148+
struct memc_flexspi_aps6408l_data *data = dev->data;
149+
uint32_t buffer = 0;
150+
int ret;
151+
152+
flexspi_transfer_t transfer = {
153+
.deviceAddress = reg,
154+
.port = config->port,
155+
.cmdType = kFLEXSPI_Read,
156+
.SeqNumber = 1,
157+
.seqIndex = READ_REG,
158+
.data = &buffer,
159+
.dataSize = 1,
160+
};
161+
162+
ret = memc_flexspi_transfer(data->controller, &transfer);
163+
if (ret < 0) {
164+
return ret;
165+
}
166+
167+
buffer &= (~mask & 0xFF);
168+
buffer |= set_val;
169+
170+
LOG_DBG("Setting reg 0x%0x to 0x%0x", reg, buffer);
171+
172+
transfer.cmdType = kFLEXSPI_Write,
173+
transfer.seqIndex = WRITE_REG;
174+
175+
ret = memc_flexspi_transfer(data->controller, &transfer);
176+
return ret;
177+
}
178+
179+
static int memc_flexspi_aps6408l_reset(const struct device *dev)
180+
{
181+
const struct memc_flexspi_aps6408l_config *config = dev->config;
182+
struct memc_flexspi_aps6408l_data *data = dev->data;
183+
int ret;
184+
185+
flexspi_transfer_t transfer = {
186+
.deviceAddress = 0x0,
187+
.port = config->port,
188+
.cmdType = kFLEXSPI_Command,
189+
.SeqNumber = 1,
190+
.seqIndex = RESET,
191+
.data = NULL,
192+
.dataSize = 0,
193+
};
194+
195+
LOG_DBG("Resetting ram");
196+
ret = memc_flexspi_transfer(data->controller, &transfer);
197+
if (ret < 0) {
198+
return ret;
199+
}
200+
/* We need to delay 5 ms to allow APS6408L pSRAM to reinitialize */
201+
k_msleep(5);
202+
203+
return ret;
204+
}
205+
206+
static int memc_flexspi_aps6408l_init(const struct device *dev)
207+
{
208+
const struct memc_flexspi_aps6408l_config *config = dev->config;
209+
struct memc_flexspi_aps6408l_data *data = dev->data;
210+
uint8_t vendor_id;
211+
212+
if (!device_is_ready(data->controller)) {
213+
LOG_ERR("Controller device not ready");
214+
return -ENODEV;
215+
}
216+
217+
if (memc_flexspi_set_device_config(data->controller, &config->config,
218+
config->port)) {
219+
LOG_ERR("Could not set device configuration");
220+
return -EINVAL;
221+
}
222+
223+
if (memc_flexspi_update_lut(data->controller, 0,
224+
(const uint32_t *) memc_flexspi_aps6408l_lut,
225+
sizeof(memc_flexspi_aps6408l_lut) / 4)) {
226+
LOG_ERR("Could not update lut");
227+
return -EINVAL;
228+
}
229+
230+
memc_flexspi_reset(data->controller);
231+
232+
if (memc_flexspi_aps6408l_reset(dev)) {
233+
LOG_ERR("Could not reset pSRAM");
234+
return -EIO;
235+
}
236+
237+
if (memc_flexspi_aps6408l_get_vendor_id(dev, &vendor_id)) {
238+
LOG_ERR("Could not read vendor id");
239+
return -EIO;
240+
}
241+
LOG_DBG("Vendor id: 0x%0x", vendor_id);
242+
if (vendor_id != APM_VENDOR_ID) {
243+
LOG_WRN("Vendor ID does not match expected value of 0x%0x",
244+
APM_VENDOR_ID);
245+
}
246+
247+
/* Enable RBX, burst length set to 1K byte wrap.
248+
* this will also enable boundary crossing for burst reads
249+
*/
250+
if (memc_flexspi_aps6408l_update_reg(dev, APS_6408L_MR_8,
251+
(APS_6408L_ROW_CROSS_MASK | APS_6408L_BURST_TYPE_MASK),
252+
(APS_6408L_ROW_CROSS_EN | APS_6408L_BURST_1K))) {
253+
LOG_ERR("Could not enable RBX 1K burst length");
254+
return -EIO;
255+
}
256+
257+
/* Set read latency code and type for 200MHz flash clock operation */
258+
if (memc_flexspi_aps6408l_update_reg(dev, APS_6408L_MR_0,
259+
(APS_6408L_RLC_MASK | APS_6408L_RLT_MASK),
260+
(APS_6408L_RLC_200 | APS_6408L_RLT_VARIABLE))) {
261+
LOG_ERR("Could not set 200MHz read latency code");
262+
return -EIO;
263+
}
264+
/* Set write latency code and type for 200MHz flash clock operation */
265+
if (memc_flexspi_aps6408l_update_reg(dev, APS_6408L_MR_4,
266+
APS_6408L_WLC_MASK, APS_6408L_WLC_200)) {
267+
LOG_ERR("Could not set 200MHz write latency code");
268+
return -EIO;
269+
}
270+
271+
return 0;
272+
}
273+
274+
#define CONCAT3(x, y, z) x ## y ## z
275+
276+
#define CS_INTERVAL_UNIT(unit) \
277+
CONCAT3(kFLEXSPI_CsIntervalUnit, unit, SckCycle)
278+
279+
#define AHB_WRITE_WAIT_UNIT(unit) \
280+
CONCAT3(kFLEXSPI_AhbWriteWaitUnit, unit, AhbCycle)
281+
282+
#define MEMC_FLEXSPI_DEVICE_CONFIG(n) \
283+
{ \
284+
.flexspiRootClk = DT_INST_PROP(n, spi_max_frequency), \
285+
.isSck2Enabled = false, \
286+
.flashSize = DT_INST_PROP(n, size) / 8 / KB(1), \
287+
.CSIntervalUnit = \
288+
CS_INTERVAL_UNIT( \
289+
DT_INST_PROP(n, cs_interval_unit)), \
290+
.CSInterval = DT_INST_PROP(n, cs_interval), \
291+
.CSHoldTime = DT_INST_PROP(n, cs_hold_time), \
292+
.CSSetupTime = DT_INST_PROP(n, cs_setup_time), \
293+
.dataValidTime = DT_INST_PROP(n, data_valid_time), \
294+
.columnspace = DT_INST_PROP(n, column_space), \
295+
.enableWordAddress = DT_INST_PROP(n, word_addressable), \
296+
.AWRSeqIndex = WRITE_DATA, \
297+
.AWRSeqNumber = 1, \
298+
.ARDSeqIndex = READ_DATA, \
299+
.ARDSeqNumber = 1, \
300+
.AHBWriteWaitUnit = \
301+
AHB_WRITE_WAIT_UNIT( \
302+
DT_INST_PROP(n, ahb_write_wait_unit)), \
303+
.AHBWriteWaitInterval = \
304+
DT_INST_PROP(n, ahb_write_wait_interval), \
305+
.enableWriteMask = true, \
306+
} \
307+
308+
#define MEMC_FLEXSPI_APS6408L(n) \
309+
static const struct memc_flexspi_aps6408l_config \
310+
memc_flexspi_aps6408l_config_##n = { \
311+
.port = DT_INST_REG_ADDR(n), \
312+
.config = MEMC_FLEXSPI_DEVICE_CONFIG(n), \
313+
}; \
314+
\
315+
static struct memc_flexspi_aps6408l_data \
316+
memc_flexspi_aps6408l_data_##n = { \
317+
.controller = DEVICE_DT_GET(DT_INST_BUS(n)), \
318+
}; \
319+
\
320+
DEVICE_DT_INST_DEFINE(n, \
321+
memc_flexspi_aps6408l_init, \
322+
NULL, \
323+
&memc_flexspi_aps6408l_data_##n, \
324+
&memc_flexspi_aps6408l_config_##n, \
325+
POST_KERNEL, \
326+
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
327+
NULL);
328+
329+
DT_INST_FOREACH_STATUS_OKAY(MEMC_FLEXSPI_APS6408L)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright 2022 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: AP Memory APS6408L pSRAM on NXP FlexSPI bus
5+
6+
compatible: "nxp,imx-flexspi-aps6408l"
7+
8+
include: nxp,imx-flexspi-device.yaml

0 commit comments

Comments
 (0)