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