1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2019-06-27     misonyo     the first version.
9  * 2022-09-01     xjy198903   add support for imxrt1170
10  */
11 
12 #include <rtthread.h>
13 #ifdef BSP_USING_CAN
14 
15 #include <rtdevice.h>
16 #include "drv_can.h"
17 #include "fsl_common.h"
18 #include "fsl_iomuxc.h"
19 #include "fsl_flexcan.h"
20 
21 #define LOG_TAG    "drv.can"
22 #include <drv_log.h>
23 
24 #if defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL
25     #error "Please don't define 'FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL'!"
26 #endif
27 
28 #define RX_MB_COUNT     32
29 static flexcan_frame_t frame[RX_MB_COUNT];    /* one frame buffer per RX MB */
30 static rt_uint32_t filter_mask = 0;
31 
32 #ifdef SOC_IMXRT1170_SERIES
33 #define USE_IMPROVED_TIMING_CONFIG (1U)
34 #endif
35 
36 enum
37 {
38 #ifdef BSP_USING_CAN1
39     CAN1_INDEX,
40 #endif
41 #ifdef BSP_USING_CAN2
42     CAN2_INDEX,
43 #endif
44 #ifdef BSP_USING_CAN3
45     CAN3_INDEX,
46 #endif
47 };
48 
49 struct imxrt_can
50 {
51     char *name;
52     CAN_Type *base;
53     IRQn_Type irqn;
54     flexcan_handle_t handle;
55     struct rt_can_device can_dev;
56 };
57 
58 struct imxrt_can flexcans[] =
59 {
60 #ifdef BSP_USING_CAN1
61     {
62         .name = "can1",
63         .base = CAN1,
64         .irqn = CAN1_IRQn,
65     },
66 #endif
67 #ifdef BSP_USING_CAN2
68     {
69         .name = "can2",
70         .base = CAN2,
71         .irqn = CAN2_IRQn,
72     },
73 #endif
74 #ifdef BSP_USING_CAN3
75     {
76         .name = "can3",
77         .base = CAN3,
78         .irqn = CAN3_IRQn,
79     },
80 #endif
81 };
82 
GetCanSrcFreq(CAN_Type * can_base)83 uint32_t GetCanSrcFreq(CAN_Type *can_base)
84 {
85     uint32_t freq;
86 #ifdef SOC_IMXRT1170_SERIES
87     uint32_t base = (uint32_t) can_base;
88     switch (base)
89         {
90         case CAN1_BASE:
91             freq = (CLOCK_GetRootClockFreq(kCLOCK_Root_Can1) / 100000U) * 100000U;
92             break;
93         case CAN2_BASE:
94             freq = (CLOCK_GetRootClockFreq(kCLOCK_Root_Can2) / 100000U) * 100000U;
95             break;
96         case CAN3_BASE:
97             freq = (CLOCK_GetRootClockFreq(kCLOCK_Root_Can3) / 100000U) * 100000U;
98             break;
99         default:
100             freq = (CLOCK_GetRootClockFreq(kCLOCK_Root_Can3) / 100000U) * 100000U;
101             break;
102         }
103 #else
104     freq = (CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 6) / (CLOCK_GetDiv(kCLOCK_CanDiv) + 1U);
105 #endif
106     return freq;
107 }
108 
109 #ifdef SOC_IMXRT1170_SERIES
flexcan_callback(CAN_Type * base,flexcan_handle_t * handle,status_t status,uint64_t result,void * userData)110 static void flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint64_t result, void *userData)
111 #else
112 static void flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData)
113 #endif
114 {
115     struct imxrt_can *can;
116     flexcan_mb_transfer_t rxXfer;
117 
118     can = (struct imxrt_can *)userData;
119     switch (status)
120     {
121     case kStatus_FLEXCAN_RxIdle:
122         rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_RX_IND | result << 8);
123         rxXfer.frame = &frame[result - 1];
124         rxXfer.mbIdx = result;
125         FLEXCAN_TransferReceiveNonBlocking(can->base, &can->handle, &rxXfer);
126         break;
127 
128     case kStatus_FLEXCAN_TxIdle:
129         rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_TX_DONE | (63 - result) << 8);
130         break;
131 
132     case kStatus_FLEXCAN_WakeUp:
133 
134     case kStatus_FLEXCAN_ErrorStatus:
135         if ((result >= 47) && (result <= 63))
136         {
137             rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_TX_FAIL | (63 - result) << 8);
138         }
139         break;
140 
141     case kStatus_FLEXCAN_TxSwitchToRx:
142         break;
143 
144     default:
145         break;
146     }
147 }
148 
can_cfg(struct rt_can_device * can_dev,struct can_configure * cfg)149 static rt_err_t can_cfg(struct rt_can_device *can_dev, struct can_configure *cfg)
150 {
151     struct imxrt_can *can;
152     flexcan_config_t config;
153     rt_uint32_t res = RT_EOK;
154     flexcan_rx_mb_config_t mbConfig;
155     flexcan_mb_transfer_t rxXfer;
156     rt_uint8_t i, mailbox;
157 
158     RT_ASSERT(can_dev != RT_NULL);
159     RT_ASSERT(cfg != RT_NULL);
160 
161     can = (struct imxrt_can *)can_dev->parent.user_data;
162     RT_ASSERT(can != RT_NULL);
163 
164     FLEXCAN_GetDefaultConfig(&config);
165     config.baudRate = cfg->baud_rate;
166     config.maxMbNum = 64;               /* all series have 64 MB */
167     config.enableIndividMask = true;    /* one filter per MB */
168     switch (cfg->mode)
169     {
170     case RT_CAN_MODE_NORMAL:
171         /* default mode */
172         break;
173     case RT_CAN_MODE_LISTEN:
174         break;
175     case RT_CAN_MODE_LOOPBACK:
176         config.enableLoopBack = true;
177         break;
178     case RT_CAN_MODE_LOOPBACKANLISTEN:
179         break;
180     }
181 
182 #ifdef SOC_IMXRT1170_SERIES
183     flexcan_timing_config_t timing_config;
184     rt_memset(&timing_config, 0, sizeof(flexcan_timing_config_t));
185 
186     if(FLEXCAN_CalculateImprovedTimingValues(can->base, config.baudRate, GetCanSrcFreq(can->base), &timing_config))
187     {
188         /* Update the improved timing configuration*/
189         rt_memcpy(&(config.timingConfig), &timing_config, sizeof(flexcan_timing_config_t));
190     }
191     else
192     {
193         LOG_E("No found Improved Timing Configuration. Just used default configuration\n");
194     }
195 #endif
196 
197     FLEXCAN_Init(can->base, &config, GetCanSrcFreq(can->base));
198     FLEXCAN_TransferCreateHandle(can->base, &can->handle, flexcan_callback, can);
199     /* init RX_MB_COUNT RX MB to default status */
200     mbConfig.format = kFLEXCAN_FrameFormatStandard;  /* standard ID */
201     mbConfig.type = kFLEXCAN_FrameTypeData;          /* data frame */
202     mbConfig.id = FLEXCAN_ID_STD(0);                 /* default ID is 0 */
203     for (i = 0; i < RX_MB_COUNT; i++)
204     {
205         /* the used MB index from 1 to RX_MB_COUNT */
206         mailbox = i + 1;
207         /* all ID bit in the filter is "don't care" */
208         FLEXCAN_SetRxIndividualMask(can->base, mailbox, FLEXCAN_RX_MB_STD_MASK(0, 0, 0));
209         FLEXCAN_SetRxMbConfig(can->base, mailbox, &mbConfig, true);
210         /* one frame buffer per MB */
211         rxXfer.frame = &frame[i];
212         rxXfer.mbIdx = mailbox;
213         FLEXCAN_TransferReceiveNonBlocking(can->base, &can->handle, &rxXfer);
214     }
215 
216     return res;
217 }
218 
can_control(struct rt_can_device * can_dev,int cmd,void * arg)219 static rt_err_t can_control(struct rt_can_device *can_dev, int cmd, void *arg)
220 {
221     struct imxrt_can *can;
222     rt_uint32_t argval, mask;
223     rt_uint32_t res = RT_EOK;
224     flexcan_rx_mb_config_t mbConfig;
225     struct rt_can_filter_config  *cfg;
226     struct rt_can_filter_item *item;
227     rt_uint8_t i, count, index;
228 
229     RT_ASSERT(can_dev != RT_NULL);
230 
231     can = (struct imxrt_can *)can_dev->parent.user_data;
232     RT_ASSERT(can != RT_NULL);
233 
234     switch (cmd)
235     {
236     case RT_DEVICE_CTRL_SET_INT:
237         argval = (rt_uint32_t) arg;
238         if (argval == RT_DEVICE_FLAG_INT_RX)
239         {
240             mask = kFLEXCAN_RxWarningInterruptEnable;
241         }
242         else if (argval == RT_DEVICE_FLAG_INT_TX)
243         {
244             mask = kFLEXCAN_TxWarningInterruptEnable;
245         }
246         else if (argval == RT_DEVICE_CAN_INT_ERR)
247         {
248             mask = kFLEXCAN_ErrorInterruptEnable;
249         }
250         FLEXCAN_EnableInterrupts(can->base, mask);
251         NVIC_SetPriority(can->irqn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
252         EnableIRQ(can->irqn);
253         break;
254     case RT_DEVICE_CTRL_CLR_INT:
255         /* each CAN device have one IRQ number. */
256         DisableIRQ(can->irqn);
257         break;
258     case RT_CAN_CMD_SET_FILTER:
259         cfg = (struct rt_can_filter_config *)arg;
260         item = cfg->items;
261         count = cfg->count;
262 
263         if (filter_mask == 0xffffffff)
264         {
265             LOG_E("%s filter is full!\n", can->name);
266             res = -RT_ERROR;
267             break;
268         }
269         else if (filter_mask == 0)
270         {
271             /* deinit all init RX MB */
272             for (i = 0; i < RX_MB_COUNT; i++)
273             {
274                 FLEXCAN_SetRxMbConfig(can->base, i + 1, RT_NULL, false);
275             }
276         }
277 
278         while (count)
279         {
280             if (item->ide)
281             {
282                 mbConfig.format = kFLEXCAN_FrameFormatExtend;
283                 mbConfig.id = FLEXCAN_ID_EXT(item->id);
284                 mask = FLEXCAN_RX_MB_EXT_MASK(item->mask, 0, 0);
285             }
286             else
287             {
288                 mbConfig.format = kFLEXCAN_FrameFormatStandard;
289                 mbConfig.id = FLEXCAN_ID_STD(item->id);
290                 mask = FLEXCAN_RX_MB_STD_MASK(item->mask, 0, 0);
291             }
292 
293             if (item->rtr)
294             {
295                 mbConfig.type = kFLEXCAN_FrameTypeRemote;
296             }
297             else
298             {
299                 mbConfig.type = kFLEXCAN_FrameTypeData;
300             }
301 
302             /* user does not specify hdr index,set hdr_bank from RX MB 1 */
303             if (item->hdr_bank == -1)
304             {
305 
306                 for (i = 0; i < 32; i++)
307                 {
308                     if (!(filter_mask & (1 << i)))
309                     {
310                         index = i;
311                         break;
312                     }
313                 }
314             }
315             else    /* use user specified hdr_bank */
316             {
317                 if (filter_mask & (1 << item->hdr_bank))
318                 {
319                     res = -RT_ERROR;
320                     LOG_E("%s hdr%d filter already set!\n", can->name, item->hdr_bank);
321                     break;
322                 }
323                 else
324                 {
325                     index = item->hdr_bank;
326                 }
327             }
328 
329             /* RX MB index from 1 to 32,hdr index 0~31 map RX MB index 1~32. */
330             FLEXCAN_SetRxIndividualMask(can->base, index + 1, mask);
331             FLEXCAN_SetRxMbConfig(can->base, index + 1, &mbConfig, true);
332             filter_mask |= 1 << index;
333 
334             item++;
335             count--;
336         }
337 
338         break;
339 
340     case RT_CAN_CMD_SET_BAUD:
341         res = -RT_ERROR;
342         break;
343     case RT_CAN_CMD_SET_MODE:
344         res = -RT_ERROR;
345         break;
346 
347     case RT_CAN_CMD_SET_PRIV:
348         res = -RT_ERROR;
349         break;
350     case RT_CAN_CMD_GET_STATUS:
351         FLEXCAN_GetBusErrCount(can->base, (rt_uint8_t *)(&can->can_dev.status.snderrcnt), (rt_uint8_t *)(&can->can_dev.status.rcverrcnt));
352         rt_memcpy(arg, &can->can_dev.status, sizeof(can->can_dev.status));
353         break;
354     default:
355         res = -RT_ERROR;
356         break;
357     }
358 
359     return res;
360 }
361 
can_send(struct rt_can_device * can_dev,const void * buf,rt_uint32_t boxno)362 static rt_ssize_t can_send(struct rt_can_device *can_dev, const void *buf, rt_uint32_t boxno)
363 {
364     struct imxrt_can *can;
365     struct rt_can_msg *msg;
366     status_t ret;
367     flexcan_frame_t frame;
368     flexcan_mb_transfer_t txXfer;
369     rt_uint8_t sendMB;
370 
371     RT_ASSERT(can_dev != RT_NULL);
372     RT_ASSERT(buf != RT_NULL);
373 
374     can = (struct imxrt_can *)can_dev->parent.user_data;
375     msg = (struct rt_can_msg *) buf;
376     RT_ASSERT(can != RT_NULL);
377     RT_ASSERT(msg != RT_NULL);
378 
379     /* use the last 16 MB to send msg */
380     sendMB = 63 - boxno;
381     FLEXCAN_SetTxMbConfig(can->base, sendMB, true);
382 
383     if (RT_CAN_STDID == msg->ide)
384     {
385         frame.id = FLEXCAN_ID_STD(msg->id);
386         frame.format = kFLEXCAN_FrameFormatStandard;
387     }
388     else if (RT_CAN_EXTID == msg->ide)
389     {
390         frame.id = FLEXCAN_ID_EXT(msg->id);
391         frame.format = kFLEXCAN_FrameFormatExtend;
392     }
393 
394     if (RT_CAN_DTR == msg->rtr)
395     {
396         frame.type = kFLEXCAN_FrameTypeData;
397     }
398     else if (RT_CAN_RTR == msg->rtr)
399     {
400         frame.type = kFLEXCAN_FrameTypeRemote;
401     }
402 
403     frame.length = msg->len;
404     frame.dataByte0 = msg->data[0];
405     frame.dataByte1 = msg->data[1];
406     frame.dataByte2 = msg->data[2];
407     frame.dataByte3 = msg->data[3];
408     frame.dataByte4 = msg->data[4];
409     frame.dataByte5 = msg->data[5];
410     frame.dataByte6 = msg->data[6];
411     frame.dataByte7 = msg->data[7];
412 
413     txXfer.mbIdx = sendMB;
414     txXfer.frame = &frame;
415 
416     ret = FLEXCAN_TransferSendNonBlocking(can->base, &can->handle, &txXfer);
417     switch (ret)
418     {
419     case kStatus_Success:
420         ret = RT_EOK;
421         break;
422     case kStatus_Fail:
423         ret = -RT_ERROR;
424         break;
425     case kStatus_FLEXCAN_TxBusy:
426         ret = -RT_EBUSY;
427         break;
428     }
429 
430     return (rt_ssize_t)ret;
431 }
432 
can_recv(struct rt_can_device * can_dev,void * buf,rt_uint32_t boxno)433 static rt_ssize_t can_recv(struct rt_can_device *can_dev, void *buf, rt_uint32_t boxno)
434 {
435     struct imxrt_can *can;
436     struct rt_can_msg *pmsg;
437     rt_uint8_t index;
438 
439     RT_ASSERT(can_dev != RT_NULL);
440 
441     can = (struct imxrt_can *)can_dev->parent.user_data;
442     pmsg = (struct rt_can_msg *) buf;
443     RT_ASSERT(can != RT_NULL);
444 
445     index = boxno - 1;
446 
447     if (frame[index].format == kFLEXCAN_FrameFormatStandard)
448     {
449         pmsg->ide = RT_CAN_STDID;
450         pmsg->id = frame[index].id >> CAN_ID_STD_SHIFT;
451     }
452     else
453     {
454         pmsg->ide = RT_CAN_EXTID;
455         pmsg->id = frame[index].id >> CAN_ID_EXT_SHIFT;
456     }
457 
458     if (frame[index].type == kFLEXCAN_FrameTypeData)
459     {
460         pmsg->rtr = RT_CAN_DTR;
461     }
462     else if (frame[index].type == kFLEXCAN_FrameTypeRemote)
463     {
464         pmsg->rtr = RT_CAN_RTR;
465     }
466     pmsg->hdr_index = index;      /* one hdr filter per MB */
467     pmsg->len = frame[index].length;
468     pmsg->data[0] = frame[index].dataByte0;
469     pmsg->data[1] = frame[index].dataByte1;
470     pmsg->data[2] = frame[index].dataByte2;
471     pmsg->data[3] = frame[index].dataByte3;
472     pmsg->data[4] = frame[index].dataByte4;
473     pmsg->data[5] = frame[index].dataByte5;
474     pmsg->data[6] = frame[index].dataByte6;
475     pmsg->data[7] = frame[index].dataByte7;
476 
477     return 0;
478 }
479 
480 static struct rt_can_ops imxrt_can_ops =
481 {
482     .configure    = can_cfg,
483     .control      = can_control,
484     .sendmsg      = can_send,
485     .recvmsg      = can_recv,
486 };
487 
rt_hw_can_init(void)488 int rt_hw_can_init(void)
489 {
490     int i;
491     rt_err_t ret = RT_EOK;
492     struct can_configure config = CANDEFAULTCONFIG;
493 
494     config.privmode = 0;
495     config.ticks = 50;
496     config.sndboxnumber = 16;             /* send Mailbox count */
497     config.msgboxsz = RX_MB_COUNT;        /* RX msg buffer count */
498 #ifdef RT_CAN_USING_HDR
499     config.maxhdr = RX_MB_COUNT;          /* filter count,one filter per MB */
500 #endif
501 
502     for (i = 0; i < sizeof(flexcans) / sizeof(flexcans[0]); i++)
503     {
504         flexcans[i].can_dev.config = config;
505         ret = rt_hw_can_register(&flexcans[i].can_dev, flexcans[i].name, &imxrt_can_ops, &flexcans[i]);
506     }
507 
508     return ret;
509 }
510 INIT_BOARD_EXPORT(rt_hw_can_init);
511 
512 #endif /* BSP_USING_CAN */
513