1 /*
2  * Copyright (c) 2022 Vestas Wind Systems A/S
3  * Copyright (c) 2022 Blue Clover
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/drivers/can.h>
9 #include <zephyr/drivers/can/can_mcan.h>
10 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
11 #include <zephyr/drivers/clock_control.h>
12 #include <zephyr/drivers/pinctrl.h>
13 #include <zephyr/kernel.h>
14 #include <stm32_ll_rcc.h>
15 #include <zephyr/logging/log.h>
16 #include <zephyr/irq.h>
17 #include <zephyr/sys/util.h>
18 
19 LOG_MODULE_REGISTER(can_stm32h7, CONFIG_CAN_LOG_LEVEL);
20 
21 #define DT_DRV_COMPAT st_stm32h7_fdcan
22 
23 /* This symbol takes the value 1 if one of the device instances */
24 /* is configured in dts with a domain clock */
25 #if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT
26 #define STM32H7_FDCAN_DOMAIN_CLOCK_SUPPORT 1
27 #else
28 #define STM32H7_FDCAN_DOMAIN_CLOCK_SUPPORT 0
29 #endif
30 
31 #define VOS0_MAX_FREQ	MHZ(125)
32 
33 struct can_stm32h7_config {
34 	mm_reg_t base;
35 	mem_addr_t mrba;
36 	mem_addr_t mram;
37 	void (*config_irq)(void);
38 	const struct pinctrl_dev_config *pcfg;
39 	size_t pclk_len;
40 	const struct stm32_pclken *pclken;
41 	uint8_t clock_divider;
42 };
43 
can_stm32h7_read_reg(const struct device * dev,uint16_t reg,uint32_t * val)44 static int can_stm32h7_read_reg(const struct device *dev, uint16_t reg, uint32_t *val)
45 {
46 	const struct can_mcan_config *mcan_cfg = dev->config;
47 	const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom;
48 
49 	return can_mcan_sys_read_reg(stm32h7_cfg->base, reg, val);
50 }
51 
can_stm32h7_write_reg(const struct device * dev,uint16_t reg,uint32_t val)52 static int can_stm32h7_write_reg(const struct device *dev, uint16_t reg, uint32_t val)
53 {
54 	const struct can_mcan_config *mcan_cfg = dev->config;
55 	const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom;
56 
57 	return can_mcan_sys_write_reg(stm32h7_cfg->base, reg, val);
58 }
59 
can_stm32h7_read_mram(const struct device * dev,uint16_t offset,void * dst,size_t len)60 static int can_stm32h7_read_mram(const struct device *dev, uint16_t offset, void *dst, size_t len)
61 {
62 	const struct can_mcan_config *mcan_cfg = dev->config;
63 	const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom;
64 
65 	return can_mcan_sys_read_mram(stm32h7_cfg->mram, offset, dst, len);
66 }
67 
can_stm32h7_write_mram(const struct device * dev,uint16_t offset,const void * src,size_t len)68 static int can_stm32h7_write_mram(const struct device *dev, uint16_t offset, const void *src,
69 				size_t len)
70 {
71 	const struct can_mcan_config *mcan_cfg = dev->config;
72 	const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom;
73 
74 	return can_mcan_sys_write_mram(stm32h7_cfg->mram, offset, src, len);
75 }
76 
can_stm32h7_clear_mram(const struct device * dev,uint16_t offset,size_t len)77 static int can_stm32h7_clear_mram(const struct device *dev, uint16_t offset, size_t len)
78 {
79 	const struct can_mcan_config *mcan_cfg = dev->config;
80 	const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom;
81 
82 	return can_mcan_sys_clear_mram(stm32h7_cfg->mram, offset, len);
83 }
84 
can_stm32h7_get_core_clock(const struct device * dev,uint32_t * rate)85 static int can_stm32h7_get_core_clock(const struct device *dev, uint32_t *rate)
86 {
87 	const uint32_t rate_tmp = LL_RCC_GetFDCANClockFreq(LL_RCC_FDCAN_CLKSOURCE);
88 	uint32_t cdiv;
89 
90 	ARG_UNUSED(dev);
91 
92 	if (rate_tmp == LL_RCC_PERIPH_FREQUENCY_NO) {
93 		LOG_ERR("Can't read core clock");
94 		return -EIO;
95 	}
96 
97 	cdiv = FIELD_GET(FDCANCCU_CCFG_CDIV, FDCAN_CCU->CCFG);
98 	if (cdiv == 0U) {
99 		*rate = rate_tmp;
100 	} else {
101 		*rate = rate_tmp / (cdiv << 1U);
102 	}
103 
104 	return 0;
105 }
106 
can_stm32h7_clock_enable(const struct device * dev)107 static int can_stm32h7_clock_enable(const struct device *dev)
108 {
109 	const struct can_mcan_config *mcan_cfg = dev->config;
110 	const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom;
111 	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
112 	uint32_t fdcan_clock = 0xffffffff;
113 	int ret;
114 
115 	if (!device_is_ready(clk)) {
116 		LOG_ERR("clock control device not ready");
117 		return -ENODEV;
118 	}
119 
120 	if (IS_ENABLED(STM32H7_FDCAN_DOMAIN_CLOCK_SUPPORT) && (stm32h7_cfg->pclk_len > 1)) {
121 		ret = clock_control_configure(clk,
122 				(clock_control_subsys_t)&stm32h7_cfg->pclken[1],
123 				NULL);
124 		if (ret < 0) {
125 			LOG_ERR("Could not select can_stm32fd domain clock");
126 			return ret;
127 		}
128 
129 		/* Check if clock has correct range according to chosen regulator voltage
130 		 * scaling (Table 62 of RM0399 Rev 4).
131 		 * There is no need to test HSE case, since it's value is in range of
132 		 * 4 to 50 MHz (please refer to CubeMX clock control).
133 		 */
134 		ret = clock_control_get_rate(clk,
135 			(clock_control_subsys_t)&stm32h7_cfg->pclken[1], &fdcan_clock);
136 		if (ret != 0) {
137 			LOG_ERR("failure getting clock rate");
138 			return ret;
139 		}
140 
141 		if (fdcan_clock > VOS0_MAX_FREQ) {
142 			LOG_ERR("FDCAN Clock source %d exceeds max allowed %d",
143 					fdcan_clock, VOS0_MAX_FREQ);
144 			return -ENODEV;
145 		}
146 	}
147 
148 	ret = clock_control_on(clk, (clock_control_subsys_t)&stm32h7_cfg->pclken[0]);
149 	if (ret != 0) {
150 		LOG_ERR("failure enabling clock");
151 		return ret;
152 	}
153 
154 	if (stm32h7_cfg->clock_divider != 0U) {
155 		can_mcan_enable_configuration_change(dev);
156 
157 		FDCAN_CCU->CCFG = FDCANCCU_CCFG_BCC |
158 			FIELD_PREP(FDCANCCU_CCFG_CDIV, stm32h7_cfg->clock_divider >> 1U);
159 	}
160 
161 	return 0;
162 }
163 
can_stm32h7_init(const struct device * dev)164 static int can_stm32h7_init(const struct device *dev)
165 {
166 	const struct can_mcan_config *mcan_cfg = dev->config;
167 	const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom;
168 	int ret;
169 
170 	/* Configure dt provided device signals when available */
171 	ret = pinctrl_apply_state(stm32h7_cfg->pcfg, PINCTRL_STATE_DEFAULT);
172 	if (ret != 0) {
173 		LOG_ERR("CAN pinctrl setup failed (%d)", ret);
174 		return ret;
175 	}
176 
177 	ret = can_stm32h7_clock_enable(dev);
178 	if (ret != 0) {
179 		return ret;
180 	}
181 
182 	ret = can_mcan_configure_mram(dev, stm32h7_cfg->mrba, stm32h7_cfg->mram);
183 	if (ret != 0) {
184 		return ret;
185 	}
186 
187 	ret = can_mcan_init(dev);
188 	if (ret != 0) {
189 		return ret;
190 	}
191 
192 	stm32h7_cfg->config_irq();
193 
194 	return 0;
195 }
196 
197 static const struct can_driver_api can_stm32h7_driver_api = {
198 	.get_capabilities = can_mcan_get_capabilities,
199 	.start = can_mcan_start,
200 	.stop = can_mcan_stop,
201 	.set_mode = can_mcan_set_mode,
202 	.set_timing = can_mcan_set_timing,
203 	.send = can_mcan_send,
204 	.add_rx_filter = can_mcan_add_rx_filter,
205 	.remove_rx_filter = can_mcan_remove_rx_filter,
206 	.get_state = can_mcan_get_state,
207 #ifdef CONFIG_CAN_MANUAL_RECOVERY_MODE
208 	.recover = can_mcan_recover,
209 #endif /* CONFIG_CAN_MANUAL_RECOVERY_MODE*/
210 	.get_core_clock = can_stm32h7_get_core_clock,
211 	.get_max_filters = can_mcan_get_max_filters,
212 	.set_state_change_callback = can_mcan_set_state_change_callback,
213 	/* Timing limits are per the STM32H7 Reference Manual (RM0433 Rev 7),
214 	 * section 56.5.7, FDCAN nominal bit timing and prescaler register
215 	 * (FDCAN_NBTP).
216 	 *
217 	 * Beware that the reference manual contains a bug regarding the minimum
218 	 * values for nominal phase segments. Valid register values are 1 and up.
219 	 */
220 	.timing_min = CAN_MCAN_TIMING_MIN_INITIALIZER,
221 	.timing_max = CAN_MCAN_TIMING_MAX_INITIALIZER,
222 #ifdef CONFIG_CAN_FD_MODE
223 	.set_timing_data = can_mcan_set_timing_data,
224 	/* Data timing limits are per the STM32H7 Reference Manual
225 	 * (RM0433 Rev 7), section 56.5.3, FDCAN data bit timing and prescaler
226 	 * register (FDCAN_DBTP).
227 	 */
228 	.timing_data_min = CAN_MCAN_TIMING_DATA_MIN_INITIALIZER,
229 	.timing_data_max = CAN_MCAN_TIMING_DATA_MAX_INITIALIZER,
230 #endif
231 };
232 
233 static const struct can_mcan_ops can_stm32h7_ops = {
234 	.read_reg = can_stm32h7_read_reg,
235 	.write_reg = can_stm32h7_write_reg,
236 	.read_mram = can_stm32h7_read_mram,
237 	.write_mram = can_stm32h7_write_mram,
238 	.clear_mram = can_stm32h7_clear_mram,
239 };
240 
241 #define CAN_STM32H7_MCAN_INIT(n)					    \
242 	CAN_MCAN_DT_INST_BUILD_ASSERT_MRAM_CFG(n);			    \
243 	BUILD_ASSERT(CAN_MCAN_DT_INST_MRAM_ELEMENTS_SIZE(n) <=		    \
244 		     CAN_MCAN_DT_INST_MRAM_SIZE(n),			    \
245 		     "Insufficient Message RAM size to hold elements");	    \
246 									    \
247 	static void stm32h7_mcan_irq_config_##n(void);			    \
248 									    \
249 	PINCTRL_DT_INST_DEFINE(n);					    \
250 	CAN_MCAN_DT_INST_CALLBACKS_DEFINE(n, can_stm32h7_cbs_##n);	    \
251 									    \
252 	static const struct stm32_pclken can_stm32h7_pclken_##n[] =	    \
253 					STM32_DT_INST_CLOCKS(n);	    \
254 									    \
255 	static const struct can_stm32h7_config can_stm32h7_cfg_##n = {	    \
256 		.base = CAN_MCAN_DT_INST_MCAN_ADDR(n),			    \
257 		.mrba = CAN_MCAN_DT_INST_MRBA(n),			    \
258 		.mram = CAN_MCAN_DT_INST_MRAM_ADDR(n),			    \
259 		.config_irq = stm32h7_mcan_irq_config_##n,		    \
260 		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),		    \
261 		.pclken = can_stm32h7_pclken_##n,			    \
262 		.pclk_len = DT_INST_NUM_CLOCKS(n),			    \
263 		.clock_divider = DT_INST_PROP_OR(n, clk_divider, 0)	    \
264 	};								    \
265 									    \
266 	static const struct can_mcan_config can_mcan_cfg_##n =		    \
267 		CAN_MCAN_DT_CONFIG_INST_GET(n, &can_stm32h7_cfg_##n,	    \
268 					    &can_stm32h7_ops,		    \
269 					    &can_stm32h7_cbs_##n);	    \
270 									    \
271 	static struct can_mcan_data can_mcan_data_##n =			    \
272 		CAN_MCAN_DATA_INITIALIZER(NULL);			    \
273 									    \
274 	CAN_DEVICE_DT_INST_DEFINE(n, can_stm32h7_init, NULL,		    \
275 				  &can_mcan_data_##n,			    \
276 				  &can_mcan_cfg_##n,			    \
277 				  POST_KERNEL, CONFIG_CAN_INIT_PRIORITY,    \
278 				  &can_stm32h7_driver_api);		    \
279 									    \
280 	static void stm32h7_mcan_irq_config_##n(void)			    \
281 	{								    \
282 		LOG_DBG("Enable CAN inst" #n " IRQ");			    \
283 		IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, int0, irq),		    \
284 			DT_INST_IRQ_BY_NAME(n, int0, priority),		    \
285 			can_mcan_line_0_isr, DEVICE_DT_INST_GET(n), 0);	    \
286 		irq_enable(DT_INST_IRQ_BY_NAME(n, int0, irq));		    \
287 		IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, int1, irq),		    \
288 			DT_INST_IRQ_BY_NAME(n, int1, priority),		    \
289 			can_mcan_line_1_isr, DEVICE_DT_INST_GET(n), 0);	    \
290 		irq_enable(DT_INST_IRQ_BY_NAME(n, int1, irq));		    \
291 	}
292 
293 DT_INST_FOREACH_STATUS_OKAY(CAN_STM32H7_MCAN_INIT)
294