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