1 /*
2  * Copyright 2023 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * MRT (Multirate timer) is a lightweight timer with multiple independent channels, each capable
9  * of signalling the shared interrupt with a different period. This driver treats all the channels
10  * as separate devices adhering to the counter API. The parent device is responsible for  the
11  * initialization, interrupt handling, and any other module-wide tasks. The current implementation
12  * of this driver prioritizes minimizing image size over speed, because it is not expected for the
13  * functions to be called very often, and this IP is mostly present on low memory devices.
14  */
15 
16 #define DT_DRV_COMPAT nxp_mrt
17 
18 #include <zephyr/drivers/counter.h>
19 #include <zephyr/sys/util.h>
20 #include <zephyr/drivers/clock_control.h>
21 #include <zephyr/devicetree.h>
22 #include <zephyr/device.h>
23 #include <zephyr/irq.h>
24 #include <zephyr/drivers/reset.h>
25 
26 #include <soc.h>
27 
28 #define LOG_MODULE_NAME counter_mrt
29 #include <zephyr/logging/log.h>
30 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_COUNTER_LOG_LEVEL);
31 
32 /* Device holds a pointer to pointer to data */
33 #define MRT_CHANNEL_DATA(dev)	\
34 	(*(struct nxp_mrt_channel_data *const *const)dev->data)
35 
36 /* Device config->data is an array of data pointers ordered by channel number,
37  * dev->data is a pointer to one of these pointers in that array,
38  * so the value of the dev->data - dev->config->data is the channel index
39  */
40 #define MRT_CHANNEL_ID(dev)	\
41 	(((struct nxp_mrt_channel_data *const *)dev->data) - \
42 	((const struct nxp_mrt_config *)dev->config)->data)
43 
44 /* Specific for each channel */
45 struct nxp_mrt_channel_data {
46 	uint32_t top;
47 	counter_top_callback_t cb;
48 	void *user_data;
49 };
50 
51 /* Shared between all channels */
52 struct nxp_mrt_config {
53 	struct counter_config_info info;
54 	MRT_Type *base;
55 	const struct device *clock_dev;
56 	clock_control_subsys_t clock_subsys;
57 	void (*irq_config_func)(const struct device *dev);
58 	struct nxp_mrt_channel_data *const *data;
59 	const struct device *const *channels;
60 	const struct reset_dt_spec reset;
61 };
62 
nxp_mrt_stop(const struct device * dev)63 static int nxp_mrt_stop(const struct device *dev)
64 {
65 	const struct nxp_mrt_config *config = dev->config;
66 	MRT_Type *base = config->base;
67 	int channel_id = MRT_CHANNEL_ID(dev);
68 
69 	LOG_DBG("MRT@%p channel %d stopped", base, channel_id);
70 	LOG_WRN("MRT channel resets upon stopping");
71 
72 	/* LOAD bit and 0 ivalue allows us to forcibly stop the timer */
73 	base->CHANNEL[channel_id].INTVAL = MRT_CHANNEL_INTVAL_LOAD(1);
74 
75 	return 0;
76 }
77 
nxp_mrt_start(const struct device * dev)78 static int nxp_mrt_start(const struct device *dev)
79 {
80 	const struct nxp_mrt_config *config = dev->config;
81 	MRT_Type *base = config->base;
82 	struct nxp_mrt_channel_data *data = MRT_CHANNEL_DATA(dev);
83 	int channel_id = MRT_CHANNEL_ID(dev);
84 
85 	if (data->top <= 1) {
86 		/* Zephyr API says default should be max top value */
87 		LOG_INF("\"Started\" MRT@%p channel %d with default value %d",
88 				base, channel_id, config->info.max_top_value);
89 		data->top = config->info.max_top_value;
90 	}
91 
92 	/* Start with previously configured top value (if already running this has no effect) */
93 	base->CHANNEL[channel_id].INTVAL = data->top;
94 
95 	LOG_DBG("MRT@%p channel %d started with top value %d", base, channel_id, data->top);
96 
97 	return 0;
98 }
99 
nxp_mrt_get_value(const struct device * dev,uint32_t * ticks)100 static int nxp_mrt_get_value(const struct device *dev, uint32_t *ticks)
101 {
102 	const struct nxp_mrt_config *config = dev->config;
103 	MRT_Type *base = config->base;
104 	int channel_id = MRT_CHANNEL_ID(dev);
105 
106 	*ticks = base->CHANNEL[channel_id].TIMER & MRT_CHANNEL_TIMER_VALUE_MASK;
107 
108 	return 0;
109 }
110 
111 
nxp_mrt_set_top_value(const struct device * dev,const struct counter_top_cfg * cfg)112 static int nxp_mrt_set_top_value(const struct device *dev, const struct counter_top_cfg *cfg)
113 {
114 	const struct nxp_mrt_config *config = dev->config;
115 	MRT_Type *base = config->base;
116 	struct nxp_mrt_channel_data *data = MRT_CHANNEL_DATA(dev);
117 	int channel_id = MRT_CHANNEL_ID(dev);
118 	/* By default in Zephyr API, the counter resets on changing top value */
119 	bool reset = !(cfg->flags & COUNTER_TOP_CFG_DONT_RESET);
120 	bool active = base->CHANNEL[channel_id].STAT & MRT_CHANNEL_STAT_RUN_MASK;
121 	uint32_t current_val = base->CHANNEL[channel_id].TIMER & MRT_CHANNEL_TIMER_VALUE_MASK;
122 	int ret = 0;
123 
124 	/* Store for use by counter_start */
125 	data->top = cfg->ticks;
126 
127 	/* Used by ISR */
128 	data->cb = cfg->callback;
129 	data->user_data = cfg->user_data;
130 
131 
132 	/* If not yet started, wait for counter_start because setting reg value starts timer */
133 	if (!active) {
134 		LOG_DBG("Set MRT@%p channel %d top value to %d", base, channel_id, data->top);
135 		return ret;
136 	}
137 
138 	/* Otherwise if currently running, need to check for lateness */
139 	if (cfg->ticks < current_val) {
140 		LOG_WRN("MRT@%p channel %d received requested top value %d which is "
141 			"smaller than current count %d",
142 			base, channel_id, cfg->ticks, current_val);
143 		/* Zephyr API says return this error in case of lateness
144 		 * when COUNTER_TOP_CFG_DONT_RESET is set but can still set period
145 		 */
146 		ret = reset ? 0 : -ETIME;
147 		/* If user said not to reset, they can also clarify exception for lateness */
148 		reset |= cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE;
149 	}
150 
151 	/* Sets the top value. If we need to reset, LOAD bit does this */
152 	base->CHANNEL[channel_id].INTVAL = MRT_CHANNEL_INTVAL_IVALUE(cfg->ticks) |
153 					   MRT_CHANNEL_INTVAL_LOAD(reset ? 1 : 0);
154 
155 	LOG_DBG("Changed MRT@%p channel %d top value while active to %d",
156 			base, channel_id,
157 			base->CHANNEL[channel_id].INTVAL & MRT_CHANNEL_INTVAL_IVALUE_MASK);
158 
159 	return ret;
160 }
161 
nxp_mrt_get_top_value(const struct device * dev)162 static uint32_t nxp_mrt_get_top_value(const struct device *dev)
163 {
164 	const struct nxp_mrt_config *config = dev->config;
165 	MRT_Type *base = config->base;
166 	int channel_id = MRT_CHANNEL_ID(dev);
167 
168 	return base->CHANNEL[channel_id].INTVAL & MRT_CHANNEL_INTVAL_IVALUE_MASK;
169 }
170 
nxp_mrt_get_pending_int(const struct device * dev)171 static uint32_t nxp_mrt_get_pending_int(const struct device *dev)
172 {
173 	const struct nxp_mrt_config *config = dev->config;
174 	MRT_Type *base = config->base;
175 	int channel_id = MRT_CHANNEL_ID(dev);
176 
177 	return base->CHANNEL[channel_id].STAT & MRT_CHANNEL_STAT_INTFLAG_MASK;
178 }
179 
nxp_mrt_set_alarm(const struct device * dev,uint8_t chan_id,const struct counter_alarm_cfg * alarm_cfg)180 static inline int nxp_mrt_set_alarm(const struct device *dev,
181 				uint8_t chan_id,
182 				const struct counter_alarm_cfg *alarm_cfg)
183 {
184 	ARG_UNUSED(dev);
185 	ARG_UNUSED(chan_id);
186 	ARG_UNUSED(alarm_cfg);
187 
188 	LOG_ERR("MRT does not support alarms");
189 	return -ENOTSUP;
190 }
191 
nxp_mrt_cancel_alarm(const struct device * dev,uint8_t chan_id)192 static inline int nxp_mrt_cancel_alarm(const struct device *dev, uint8_t chan_id)
193 {
194 	ARG_UNUSED(dev);
195 	ARG_UNUSED(chan_id);
196 
197 	LOG_ERR("MRT does not support alarms");
198 	return -ENOTSUP;
199 }
200 
nxp_mrt_get_freq(const struct device * dev)201 uint32_t nxp_mrt_get_freq(const struct device *dev)
202 {
203 	const struct nxp_mrt_config *config = dev->config;
204 	uint32_t freq;
205 
206 	clock_control_get_rate(config->clock_dev, config->clock_subsys, &freq);
207 
208 	return freq;
209 }
210 
nxp_mrt_init(const struct device * dev)211 static int nxp_mrt_init(const struct device *dev)
212 {
213 	const struct nxp_mrt_config *config = dev->config;
214 	MRT_Type *base = config->base;
215 	uint32_t num_channels = (base->MODCFG & MRT_MODCFG_NOC_MASK) >> MRT_MODCFG_NOC_SHIFT;
216 	int ret = 0;
217 
218 	if (!device_is_ready(config->reset.dev)) {
219 		LOG_ERR("Reset device not ready");
220 		return -ENODEV;
221 	}
222 
223 	ret = reset_line_toggle(config->reset.dev, config->reset.id);
224 	if (ret) {
225 		return ret;
226 	}
227 
228 	clock_control_on(config->clock_dev, config->clock_subsys);
229 
230 	config->irq_config_func(dev);
231 
232 	/* Enable interrupts for all the channels that have devices */
233 	for (int i = 0; i < num_channels; i++) {
234 		if (config->channels[i]) {
235 			base->CHANNEL[i].CTRL = MRT_CHANNEL_CTRL_INTEN_MASK;
236 		}
237 	}
238 
239 	return 0;
240 }
241 
nxp_mrt_isr(const struct device * dev)242 static void nxp_mrt_isr(const struct device *dev)
243 {
244 	const struct nxp_mrt_config *config = dev->config;
245 	MRT_Type *base = config->base;
246 	uint32_t irq_pends = base->IRQ_FLAG;
247 	uint32_t num_channels = (base->MODCFG & MRT_MODCFG_NOC_MASK) >> MRT_MODCFG_NOC_SHIFT;
248 
249 	for (int i = 0; i < num_channels; i++) {
250 		/* Channel IRQ pending flags lowest order bits in IRQ_FLAG register */
251 		if (!(irq_pends & (0x1 << i))) {
252 			continue;
253 		}
254 
255 		LOG_DBG("Handling interrupt for MRT%p channel %d", base, i);
256 
257 		/* W1C interrupt flag */
258 		base->CHANNEL[i].STAT |= MRT_CHANNEL_STAT_INTFLAG_MASK;
259 
260 		/* Channel devs & pointer path to channel cbs is in shared config */
261 		if (config->data[i]->cb) {
262 			config->data[i]->cb(config->channels[i], config->data[i]->user_data);
263 		}
264 	}
265 }
266 
267 struct counter_driver_api nxp_mrt_api = {
268 	.get_value = nxp_mrt_get_value,
269 	.start = nxp_mrt_start,
270 	.stop = nxp_mrt_stop,
271 	.set_top_value = nxp_mrt_set_top_value,
272 	.get_top_value = nxp_mrt_get_top_value,
273 	.get_pending_int = nxp_mrt_get_pending_int,
274 	.set_alarm = nxp_mrt_set_alarm,
275 	.cancel_alarm = nxp_mrt_cancel_alarm,
276 	.get_freq = nxp_mrt_get_freq,
277 };
278 
279 /* Creates a device for a channel (needed for counter API) */
280 #define NXP_MRT_CHANNEL_DEV_INIT(node, mrt_inst)				\
281 	DEVICE_DT_DEFINE(node, NULL, NULL,					\
282 			(void *)						\
283 			&nxp_mrt_##mrt_inst##_channel_datas[DT_REG_ADDR(node)],	\
284 			&nxp_mrt_##mrt_inst##_config,				\
285 			POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY,		\
286 			&nxp_mrt_api);						\
287 
288 /* Creates a data struct for a channel device */
289 #define NXP_MRT_CHANNEL_DATA_INIT(node)						\
290 	static struct nxp_mrt_channel_data					\
291 		nxp_mrt_channel_data_##node;					\
292 
293 /* Initializes an element of the channel data pointer array */
294 #define NXP_MRT_CHANNEL_DATA_ARRAY_INIT(node)					\
295 	[DT_REG_ADDR(node)] =							\
296 		&nxp_mrt_channel_data_##node,
297 
298 /* Initializes an element of the channel device pointer array */
299 #define NXP_MRT_CHANNEL_DEV_ARRAY_INIT(node)					\
300 	[DT_REG_ADDR(node)] = DEVICE_DT_GET(node),
301 
302 #define NXP_MRT_INIT(n)								\
303 	/* ISR is shared between all channels */				\
304 	static void nxp_mrt_##n##_irq_config_func(const struct device *dev)	\
305 	{									\
306 		IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority),		\
307 				nxp_mrt_isr, DEVICE_DT_INST_GET(n), 0);		\
308 		irq_enable(DT_INST_IRQN(n));					\
309 	}									\
310 										\
311 	/* Initialize all the data structs for active channels */		\
312 	DT_INST_FOREACH_CHILD_STATUS_OKAY(n, NXP_MRT_CHANNEL_DATA_INIT)		\
313 										\
314 	/* Create an array of const pointers to the data structs */		\
315 	static struct nxp_mrt_channel_data *const nxp_mrt_##n##_channel_datas	\
316 			[DT_INST_PROP(n, num_channels)] = {			\
317 			DT_INST_FOREACH_CHILD_STATUS_OKAY(n,			\
318 				NXP_MRT_CHANNEL_DATA_ARRAY_INIT)		\
319 	};									\
320 										\
321 	/* Forward declaration */						\
322 	const static struct nxp_mrt_config nxp_mrt_##n##_config;		\
323 										\
324 	/* Create all the channel/counter devices */				\
325 	DT_INST_FOREACH_CHILD_STATUS_OKAY_VARGS(n, NXP_MRT_CHANNEL_DEV_INIT, n)	\
326 										\
327 	/* This channel device array is needed by the module device ISR */	\
328 	const struct device *const nxp_mrt_##n##_channels			\
329 				[DT_INST_PROP(n, num_channels)] = {		\
330 			DT_INST_FOREACH_CHILD_STATUS_OKAY(n,			\
331 				NXP_MRT_CHANNEL_DEV_ARRAY_INIT)			\
332 	};									\
333 										\
334 	/* This config struct is shared by all the channels and parent device */\
335 	const static struct nxp_mrt_config nxp_mrt_##n##_config = {		\
336 		.info =	{							\
337 			.max_top_value =					\
338 			GENMASK(DT_INST_PROP(n, num_bits) - 1, 0),		\
339 			.channels = 0,						\
340 		},								\
341 		.base = (MRT_Type *)DT_INST_REG_ADDR(n),			\
342 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)),		\
343 		.clock_subsys = (clock_control_subsys_t)			\
344 				DT_INST_CLOCKS_CELL(n, name),			\
345 		.irq_config_func = nxp_mrt_##n##_irq_config_func,		\
346 		.data = nxp_mrt_##n##_channel_datas,				\
347 		.channels = nxp_mrt_##n##_channels,				\
348 		.reset = RESET_DT_SPEC_INST_GET(n),				\
349 	};									\
350 										\
351 	/* Init parent device in order to handle ISR and init. */		\
352 	DEVICE_DT_INST_DEFINE(n, &nxp_mrt_init, NULL, NULL,			\
353 				&nxp_mrt_##n##_config,				\
354 				POST_KERNEL,					\
355 				CONFIG_COUNTER_INIT_PRIORITY, NULL);
356 
357 DT_INST_FOREACH_STATUS_OKAY(NXP_MRT_INIT)
358