1 /*
2 * Copyright 2023 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "memc_nxp_flexram.h"
8 #include <zephyr/dt-bindings/memory-controller/nxp,flexram.h>
9 #include <zephyr/devicetree.h>
10 #include <zephyr/init.h>
11 #include <zephyr/sys/util.h>
12 #include <errno.h>
13 #include <zephyr/irq.h>
14
15 #include "fsl_device_registers.h"
16
17
18 #if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API)
19 BUILD_ASSERT(DT_PROP(FLEXRAM_DT_NODE, flexram_has_magic_addr),
20 "SOC does not support magic flexram addresses");
21 #endif
22
23 #define BANK_SIZE (DT_PROP(FLEXRAM_DT_NODE, flexram_bank_size) * 1024)
24 #define NUM_BANKS DT_PROP(FLEXRAM_DT_NODE, flexram_num_ram_banks)
25
26 #define IS_CHILD_RAM_TYPE(node_id, compat) DT_NODE_HAS_COMPAT(node_id, compat)
27 #define DOES_RAM_TYPE_EXIST(compat) \
28 DT_FOREACH_CHILD_SEP_VARGS(FLEXRAM_DT_NODE, IS_CHILD_RAM_TYPE, (+), compat)
29
30 #if DOES_RAM_TYPE_EXIST(mmio_sram)
31 #define FIND_OCRAM_NODE(node_id) \
32 COND_CODE_1(DT_NODE_HAS_COMPAT(node_id, mmio_sram), (node_id), ())
33 #define OCRAM_DT_NODE DT_FOREACH_CHILD(FLEXRAM_DT_NODE, FIND_OCRAM_NODE)
34 #define OCRAM_START (DT_REG_ADDR(OCRAM_DT_NODE))
35 #define OCRAM_END (OCRAM_START + DT_REG_SIZE(OCRAM_DT_NODE))
36 #endif /* OCRAM */
37 #if DOES_RAM_TYPE_EXIST(nxp_imx_dtcm)
38 #define FIND_DTCM_NODE(node_id) \
39 COND_CODE_1(DT_NODE_HAS_COMPAT(node_id, nxp_imx_dtcm), (node_id), ())
40 #define DTCM_DT_NODE DT_FOREACH_CHILD(FLEXRAM_DT_NODE, FIND_DTCM_NODE)
41 #define DTCM_START (DT_REG_ADDR(DTCM_DT_NODE))
42 #define DTCM_END (DTCM_START + DT_REG_SIZE(DTCM_DT_NODE))
43 #endif /* DTCM */
44 #if DOES_RAM_TYPE_EXIST(nxp_imx_itcm)
45 #define FIND_ITCM_NODE(node_id) \
46 COND_CODE_1(DT_NODE_HAS_COMPAT(node_id, nxp_imx_itcm), (node_id), ())
47 #define ITCM_DT_NODE DT_FOREACH_CHILD(FLEXRAM_DT_NODE, FIND_ITCM_NODE)
48 #define ITCM_START (DT_REG_ADDR(ITCM_DT_NODE))
49 #define ITCM_END (ITCM_START + DT_REG_SIZE(ITCM_DT_NODE))
50 #endif /* ITCM */
51
52
53 #ifdef FLEXRAM_RUNTIME_BANKS_USED
54
55 #define PLUS_ONE_BANK(node_id, prop, idx) 1
56 #define COUNT_BANKS \
57 DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, flexram_bank_spec, PLUS_ONE_BANK, (+))
58 BUILD_ASSERT(COUNT_BANKS == NUM_BANKS, "wrong number of flexram banks defined");
59
60 #ifdef OCRAM_DT_NODE
61 #define ADD_BANK_IF_OCRAM(node_id, prop, idx) \
62 COND_CODE_1(IS_EQ(DT_PROP_BY_IDX(node_id, prop, idx), FLEXRAM_OCRAM), \
63 (BANK_SIZE), (0))
64 #define OCRAM_TOTAL \
65 DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, flexram_bank_spec, ADD_BANK_IF_OCRAM, (+))
66 BUILD_ASSERT((OCRAM_TOTAL) == DT_REG_SIZE(OCRAM_DT_NODE), "OCRAM node size is wrong");
67 #endif /* OCRAM */
68
69 #ifdef DTCM_DT_NODE
70 #define ADD_BANK_IF_DTCM(node_id, prop, idx) \
71 COND_CODE_1(IS_EQ(DT_PROP_BY_IDX(node_id, prop, idx), FLEXRAM_DTCM), \
72 (BANK_SIZE), (0))
73 #define DTCM_TOTAL \
74 DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, flexram_bank_spec, ADD_BANK_IF_DTCM, (+))
75 BUILD_ASSERT((DTCM_TOTAL) == DT_REG_SIZE(DTCM_DT_NODE), "DTCM node size is wrong");
76 #endif /* DTCM */
77
78 #ifdef ITCM_DT_NODE
79 #define ADD_BANK_IF_ITCM(node_id, prop, idx) \
80 COND_CODE_1(IS_EQ(DT_PROP_BY_IDX(node_id, prop, idx), FLEXRAM_ITCM), \
81 (BANK_SIZE), (0))
82 #define ITCM_TOTAL \
83 DT_FOREACH_PROP_ELEM_SEP(FLEXRAM_DT_NODE, flexram_bank_spec, ADD_BANK_IF_ITCM, (+))
84 BUILD_ASSERT((ITCM_TOTAL) == DT_REG_SIZE(ITCM_DT_NODE), "ITCM node size is wrong");
85 #endif /* ITCM */
86
87 #endif /* FLEXRAM_RUNTIME_BANKS_USED */
88
89 static FLEXRAM_Type *const base = (FLEXRAM_Type *) DT_REG_ADDR(FLEXRAM_DT_NODE);
90
91 #ifdef FLEXRAM_INTERRUPTS_USED
92 static flexram_callback_t flexram_callback;
93 static void *flexram_user_data;
94
memc_flexram_register_callback(flexram_callback_t callback,void * user_data)95 void memc_flexram_register_callback(flexram_callback_t callback, void *user_data)
96 {
97 flexram_callback = callback;
98 flexram_user_data = user_data;
99 }
100
nxp_flexram_isr(void * arg)101 static void nxp_flexram_isr(void *arg)
102 {
103 ARG_UNUSED(arg);
104
105 if (flexram_callback == NULL) {
106 return;
107 }
108
109 #if defined(CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT)
110 if (base->INT_STATUS & FLEXRAM_INT_STATUS_OCRAM_ERR_STATUS_MASK) {
111 base->INT_STATUS |= FLEXRAM_INT_STATUS_OCRAM_ERR_STATUS_MASK;
112 flexram_callback(flexram_ocram_access_error, flexram_user_data);
113 }
114 if (base->INT_STATUS & FLEXRAM_INT_STATUS_DTCM_ERR_STATUS_MASK) {
115 base->INT_STATUS |= FLEXRAM_INT_STATUS_DTCM_ERR_STATUS_MASK;
116 flexram_callback(flexram_dtcm_access_error, flexram_user_data);
117 }
118 if (base->INT_STATUS & FLEXRAM_INT_STATUS_ITCM_ERR_STATUS_MASK) {
119 base->INT_STATUS |= FLEXRAM_INT_STATUS_ITCM_ERR_STATUS_MASK;
120 flexram_callback(flexram_itcm_access_error, flexram_user_data);
121 }
122 #endif /* CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT */
123
124 #if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API)
125 if (base->INT_STATUS & FLEXRAM_INT_STATUS_OCRAM_MAM_STATUS_MASK) {
126 base->INT_STATUS |= FLEXRAM_INT_STATUS_OCRAM_MAM_STATUS_MASK;
127 flexram_callback(flexram_ocram_magic_addr, flexram_user_data);
128 }
129 if (base->INT_STATUS & FLEXRAM_INT_STATUS_DTCM_MAM_STATUS_MASK) {
130 base->INT_STATUS |= FLEXRAM_INT_STATUS_DTCM_MAM_STATUS_MASK;
131 flexram_callback(flexram_dtcm_magic_addr, flexram_user_data);
132 }
133 if (base->INT_STATUS & FLEXRAM_INT_STATUS_ITCM_MAM_STATUS_MASK) {
134 base->INT_STATUS |= FLEXRAM_INT_STATUS_ITCM_MAM_STATUS_MASK;
135 flexram_callback(flexram_itcm_magic_addr, flexram_user_data);
136 }
137 #endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */
138 }
139
140 #if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API)
memc_flexram_set_ocram_magic_addr(uint32_t ocram_addr)141 int memc_flexram_set_ocram_magic_addr(uint32_t ocram_addr)
142 {
143 #ifdef OCRAM_DT_NODE
144 ocram_addr -= DT_REG_ADDR(OCRAM_DT_NODE);
145 if (ocram_addr >= DT_REG_SIZE(OCRAM_DT_NODE)) {
146 return -EINVAL;
147 }
148
149 base->OCRAM_MAGIC_ADDR &= ~FLEXRAM_OCRAM_MAGIC_ADDR_OCRAM_MAGIC_ADDR_MASK;
150 base->OCRAM_MAGIC_ADDR |= FLEXRAM_OCRAM_MAGIC_ADDR_OCRAM_MAGIC_ADDR(ocram_addr);
151
152 base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_OCRAM_MAM_STAT_EN_MASK;
153 return 0;
154 #else
155 return -ENODEV;
156 #endif
157 }
158
memc_flexram_set_itcm_magic_addr(uint32_t itcm_addr)159 int memc_flexram_set_itcm_magic_addr(uint32_t itcm_addr)
160 {
161 #ifdef ITCM_DT_NODE
162 itcm_addr -= DT_REG_ADDR(ITCM_DT_NODE);
163 if (itcm_addr >= DT_REG_SIZE(ITCM_DT_NODE)) {
164 return -EINVAL;
165 }
166
167 base->ITCM_MAGIC_ADDR &= ~FLEXRAM_ITCM_MAGIC_ADDR_ITCM_MAGIC_ADDR_MASK;
168 base->ITCM_MAGIC_ADDR |= FLEXRAM_ITCM_MAGIC_ADDR_ITCM_MAGIC_ADDR(itcm_addr);
169
170 base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_ITCM_MAM_STAT_EN_MASK;
171 return 0;
172 #else
173 return -ENODEV;
174 #endif
175 }
176
memc_flexram_set_dtcm_magic_addr(uint32_t dtcm_addr)177 int memc_flexram_set_dtcm_magic_addr(uint32_t dtcm_addr)
178 {
179 #ifdef DTCM_DT_NODE
180 dtcm_addr -= DT_REG_ADDR(DTCM_DT_NODE);
181 if (dtcm_addr >= DT_REG_SIZE(DTCM_DT_NODE)) {
182 return -EINVAL;
183 }
184
185 base->DTCM_MAGIC_ADDR &= ~FLEXRAM_DTCM_MAGIC_ADDR_DTCM_MAGIC_ADDR_MASK;
186 base->DTCM_MAGIC_ADDR |= FLEXRAM_DTCM_MAGIC_ADDR_DTCM_MAGIC_ADDR(dtcm_addr);
187
188 base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_DTCM_MAM_STAT_EN_MASK;
189 return 0;
190 #else
191 return -ENODEV;
192 #endif
193 }
194 #endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */
195
196 #endif /* FLEXRAM_INTERRUPTS_USED */
197
nxp_flexram_init(void)198 static int nxp_flexram_init(void)
199 {
200 if (DT_PROP(FLEXRAM_DT_NODE, flexram_tcm_read_wait_mode)) {
201 base->TCM_CTRL |= FLEXRAM_TCM_CTRL_TCM_WWAIT_EN_MASK;
202 }
203 if (DT_PROP(FLEXRAM_DT_NODE, flexram_tcm_write_wait_mode)) {
204 base->TCM_CTRL |= FLEXRAM_TCM_CTRL_TCM_RWAIT_EN_MASK;
205 }
206
207 #if defined(CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT)
208 base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_OCRAM_ERR_SIG_EN_MASK;
209 base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_DTCM_ERR_SIG_EN_MASK;
210 base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_ITCM_ERR_SIG_EN_MASK;
211 base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_OCRAM_ERR_STAT_EN_MASK;
212 base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_DTCM_ERR_STAT_EN_MASK;
213 base->INT_STAT_EN |= FLEXRAM_INT_STAT_EN_ITCM_ERR_STAT_EN_MASK;
214 #endif /* CONFIG_MEMC_NXP_FLEXRAM_ERROR_INTERRUPT */
215
216 #if defined(CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API)
217 base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_OCRAM_MAM_SIG_EN_MASK;
218 base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_DTCM_MAM_SIG_EN_MASK;
219 base->INT_SIG_EN |= FLEXRAM_INT_SIG_EN_ITCM_MAM_SIG_EN_MASK;
220 #endif /* CONFIG_MEMC_NXP_FLEXRAM_MAGIC_ADDR_API */
221
222 #ifdef FLEXRAM_INTERRUPTS_USED
223 IRQ_CONNECT(DT_IRQN(FLEXRAM_DT_NODE), DT_IRQ(FLEXRAM_DT_NODE, priority),
224 nxp_flexram_isr, NULL, 0);
225 irq_enable(DT_IRQN(FLEXRAM_DT_NODE));
226 #endif /* FLEXRAM_INTERRUPTS_USED */
227
228 return 0;
229 }
230
231 SYS_INIT(nxp_flexram_init, EARLY, 0);
232