-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path0021-can-add-Phytium-CAN-controller-support.patch
1724 lines (1719 loc) · 52.2 KB
/
0021-can-add-Phytium-CAN-controller-support.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
From 05486e34ce562ec2c705118e3e0b23313351ade4 Mon Sep 17 00:00:00 2001
From: Chen Baozi <[email protected]>
Date: Mon, 17 Jun 2024 19:33:01 +0800
Subject: [PATCH 021/150] can: add Phytium CAN controller support
This patch adds Phytium CAN controller support.
Signed-off-by: Cheng Quan <[email protected]>
Signed-off-by: Li Zhengguang <[email protected]>
Signed-off-by: Chen Zhenhua <[email protected]>
Signed-off-by: Wang Yinfeng <[email protected]>
Signed-off-by: Chen Baozi <[email protected]>
Change-Id: I749b46e4af35ad38435a13ff645a0b5557b4e1d5
Signed-off-by: Andrew Powers-Holmes <[email protected]>
---
MAINTAINERS | 1 +
drivers/net/can/Kconfig | 1 +
drivers/net/can/Makefile | 1 +
drivers/net/can/phytium/Kconfig | 34 +
drivers/net/can/phytium/Makefile | 8 +
drivers/net/can/phytium/phytium_can.c | 1146 +++++++++++++++++
drivers/net/can/phytium/phytium_can.h | 66 +
drivers/net/can/phytium/phytium_can_pci.c | 135 ++
.../net/can/phytium/phytium_can_platform.c | 228 ++++
9 files changed, 1620 insertions(+)
create mode 100644 drivers/net/can/phytium/Kconfig
create mode 100644 drivers/net/can/phytium/Makefile
create mode 100644 drivers/net/can/phytium/phytium_can.c
create mode 100644 drivers/net/can/phytium/phytium_can.h
create mode 100644 drivers/net/can/phytium/phytium_can_pci.c
create mode 100644 drivers/net/can/phytium/phytium_can_platform.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 492b97e22477..999ebced2fa4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2539,6 +2539,7 @@ F: arch/arm64/boot/dts/phytium/*
F: drivers/gpio/gpio-phytium*
F: drivers/mmc/host/phytium-sdci.*
F: drivers/mtd/parsers/acpipart_core.c
+F: drivers/net/can/phytium/*
F: drivers/spi/spi-phytium*
F: drivers/spi/spi-phytium-qspi.c
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index f8cde9f9f554..718331660665 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -221,6 +221,7 @@ source "drivers/net/can/ifi_canfd/Kconfig"
source "drivers/net/can/m_can/Kconfig"
source "drivers/net/can/mscan/Kconfig"
source "drivers/net/can/peak_canfd/Kconfig"
+source "drivers/net/can/phytium/Kconfig"
source "drivers/net/can/rcar/Kconfig"
source "drivers/net/can/sja1000/Kconfig"
source "drivers/net/can/softing/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index ff8f76295d13..4d40836e58b6 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_CAN_KVASER_PCIEFD) += kvaser_pciefd.o
obj-$(CONFIG_CAN_MSCAN) += mscan/
obj-$(CONFIG_CAN_M_CAN) += m_can/
obj-$(CONFIG_CAN_PEAK_PCIEFD) += peak_canfd/
+obj-$(CONFIG_CAN_PHYTIUM) += phytium/
obj-$(CONFIG_CAN_SJA1000) += sja1000/
obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
diff --git a/drivers/net/can/phytium/Kconfig b/drivers/net/can/phytium/Kconfig
new file mode 100644
index 000000000000..a23216d23c22
--- /dev/null
+++ b/drivers/net/can/phytium/Kconfig
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menuconfig CAN_PHYTIUM
+ tristate "Phytium CAN support"
+ help
+ Say Y here if you want support for Phytium CAN controller framework.
+ This is common support for devices that embed the Phytium CAN IP.
+
+ To compile this driver as a module, choose M here: the module will
+ be called phytium_can.
+
+if CAN_PHYTIUM
+
+config CAN_PHYTIUM_PLATFORM
+ tristate "Phytium CAN support for io-mapped devices"
+ depends on HAS_IOMEM
+ help
+ Say Y here is you want to support for IO Mapped Phytium CAN controller.
+ This support is for devices that have the Phytium CAN controller IP
+ embedded into the device and the IP is IO Mapped to the processor.
+
+ To compile this driver as a module, choose M here: the module will
+ be called phytium_can_platform.
+
+config CAN_PHYTIUM_PCI
+ tristate "Phytium CAN support for PCI devices"
+ depends on PCI
+ help
+ Say Y here is you want to support for Phytium CAN controller connected
+ to the PCI bus. This support is for devices that have the Phytium CAN
+ controller IP embedded into a PCI device.
+
+ To compile this driver as a module, choose M here: the module will
+ be called phytium_can_pci.
+endif
diff --git a/drivers/net/can/phytium/Makefile b/drivers/net/can/phytium/Makefile
new file mode 100644
index 000000000000..7ef554fca58e
--- /dev/null
+++ b/drivers/net/can/phytium/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Phytium CAN controller drivers.
+#
+#
+
+obj-$(CONFIG_CAN_PHYTIUM) += phytium_can.o
+obj-$(CONFIG_CAN_PHYTIUM_PLATFORM) += phytium_can_platform.o
+obj-$(CONFIG_CAN_PHYTIUM_PCI) += phytium_can_pci.o
diff --git a/drivers/net/can/phytium/phytium_can.c b/drivers/net/can/phytium/phytium_can.c
new file mode 100644
index 000000000000..21bf74a1d66f
--- /dev/null
+++ b/drivers/net/can/phytium/phytium_can.c
@@ -0,0 +1,1146 @@
+// SPDX-License-Identifier: GPL-2.0
+/* CAN bus driver for Phytium CAN controller
+ *
+ * Copyright (C) 2021-2023, Phytium Technology Co., Ltd.
+ */
+
+#include <linux/bitfield.h>
+
+#include "phytium_can.h"
+
+/* register definition */
+enum phytium_can_reg {
+ CAN_CTRL = 0x00, /* Global control register */
+ CAN_INTR = 0x04, /* Interrupt register */
+ CAN_ARB_RATE_CTRL = 0x08, /* Arbitration rate control register */
+ CAN_DAT_RATE_CTRL = 0x0c, /* Data rate control register */
+ CAN_ACC_ID0 = 0x10, /* Acceptance identifier0 register */
+ CAN_ACC_ID1 = 0x14, /* Acceptance identifier1 register */
+ CAN_ACC_ID2 = 0x18, /* Acceptance identifier2 register */
+ CAN_ACC_ID3 = 0x1c, /* Acceptance identifier3 register */
+ CAN_ACC_ID0_MASK = 0x20, /* Acceptance identifier0 mask register */
+ CAN_ACC_ID1_MASK = 0x24, /* Acceptance identifier1 mask register */
+ CAN_ACC_ID2_MASK = 0x28, /* Acceptance identifier2 mask register */
+ CAN_ACC_ID3_MASK = 0x2c, /* Acceptance identifier3 mask register */
+ CAN_XFER_STS = 0x30, /* Transfer status register */
+ CAN_ERROR_CNT = 0x34, /* Error counter register */
+ CAN_FIFO_CNT = 0x38, /* FIFO counter register */
+ CAN_DMA_CTRL = 0x3c, /* DMA request control register */
+ CAN_XFER_EN = 0x40, /* Transfer enable register */
+ CAN_INTR1 = 0x44, /* Interrupt register 1 */
+ CAN_FRM_INFO = 0x48, /* Frame valid number register */
+ CAN_TIME_OUT = 0x4c, /* Timeout register */
+ CAN_TIME_OUT_CNT = 0x50, /* Timeout counter register */
+ CAN_INTR2 = 0x54, /* Interrupt register 2 */
+ CAN_TX_FIFO = 0x100, /* TX FIFO shadow register */
+ CAN_RX_FIFO = 0x200, /* RX FIFO shadow register */
+ CAN_RX_INFO_FIFO = 0x300, /* RX information FIFO shadow register */
+ CAN_PIDR4 = 0xfd0, /* Peripheral Identification Register 4 */
+ CAN_PIDR0 = 0xfe0, /* Peripheral Identification Register 0 */
+ CAN_PIDR1 = 0xfe4, /* Peripheral Identification Register 1 */
+ CAN_PIDR2 = 0xfe8, /* Peripheral Identification Register 2 */
+ CAN_PIDR3 = 0xfec, /* Peripheral Identification Register 3 */
+ CAN_CIDR0 = 0xff0, /* Component Identification Register 0 */
+ CAN_CIDR1 = 0xff4, /* Component Identification Register 1 */
+ CAN_CIDR2 = 0xff8, /* Component Identification Register 2 */
+ CAN_CIDR3 = 0xffc, /* Component Identification Register 3 */
+};
+
+/* Global control register (CTRL) */
+#define CTRL_XFER BIT(0) /* Transfer enable */
+#define CTRL_TXREQ BIT(1) /* Transmit request */
+#define CTRL_AIME BIT(2) /* Acceptance identifier mask enable */
+#define CTRL_TTS BIT(3) /* Transmit trigger strategy */
+#define CTRL_RST BIT(7) /* Write 1 to soft reset and self clear */
+#define CTRL_RFEIDF BIT(8) /* Allow RX frame end interrupt during ID filtered frame */
+#define CTRL_RFEDT BIT(9) /* Allow RX frame end interrupt during TX frame */
+#define CTRL_IOF BIT(10) /* Ignore overload flag internally */
+#define CTRL_FDCRC BIT(11) /* CANFD CRC mode */
+
+/* Interrupt register (INTR) */
+#define INTR_BOIS BIT(0) /* Bus off interrupt status */
+#define INTR_PWIS BIT(1) /* Passive warning interrupt status */
+#define INTR_PEIS BIT(2) /* Passive error interrupt status */
+#define INTR_RFIS BIT(3) /* RX FIFO full interrupt status */
+#define INTR_TFIS BIT(4) /* TX FIFO empty interrupt status */
+#define INTR_REIS BIT(5) /* RX frame end interrupt status */
+#define INTR_TEIS BIT(6) /* TX frame end interrupt status */
+#define INTR_EIS BIT(7) /* Error interrupt status */
+#define INTR_BOIE BIT(8) /* Bus off interrupt enable */
+#define INTR_PWIE BIT(9) /* Passive warning interrupt enable */
+#define INTR_PEIE BIT(10) /* Passive error interrupt enable */
+#define INTR_RFIE BIT(11) /* RX FIFO full interrupt enable */
+#define INTR_TFIE BIT(12) /* TX FIFO empty interrupt enable */
+#define INTR_REIE BIT(13) /* RX frame end interrupt enable */
+#define INTR_TEIE BIT(14) /* TX frame end interrupt enable */
+#define INTR_EIE BIT(15) /* Error interrupt enable */
+#define INTR_BOIC BIT(16) /* Bus off interrupt clear */
+#define INTR_PWIC BIT(17) /* Passive warning interrupt clear */
+#define INTR_PEIC BIT(18) /* Passive error interrupt clear */
+#define INTR_RFIC BIT(19) /* RX FIFO full interrupt clear */
+#define INTR_TFIC BIT(20) /* TX FIFO empty interrupt clear */
+#define INTR_REIC BIT(21) /* RX frame end interrupt clear */
+#define INTR_TEIC BIT(22) /* TX frame end interrupt clear */
+#define INTR_EIC BIT(23) /* Error interrupt clear */
+
+#define INTR_STATUS_MASK (INTR_BOIS | INTR_PWIS | INTR_PEIS | INTR_RFIS | \
+ INTR_TFIS | INTR_REIS | INTR_TEIS | INTR_EIS)
+#define INTR_EN_MASK (INTR_BOIE | INTR_PWIE | INTR_PEIE | INTR_RFIE | \
+ INTR_REIE | INTR_TEIE | INTR_EIE)
+#define INTR_CLEAR_MASK (INTR_BOIC | INTR_PWIC | INTR_PEIC | INTR_RFIC | \
+ INTR_TFIC | INTR_REIC | INTR_TEIC | INTR_EIC)
+
+/* Arbitration rate control register (ARB_RATE_CTRL) */
+#define ARB_RATE_CTRL_ARJW GENMASK(1, 0) /* Arbitration field resync jump width */
+#define ARB_RATE_CTRL_APRS GENMASK(4, 2) /* Arbitration field propagation segment */
+#define ARB_RATE_CTRL_APH1S GENMASK(7, 5) /* Arbitration field phase1 segment */
+#define ARB_RATE_CTRL_APH2S GENMASK(10, 8) /* Arbitration field phase2 segment */
+#define ARB_RATE_CTRL_APD GENMASK(28, 16) /* Arbitration field prescaler divider */
+
+/* Data rate control register (DAT_RATE_CTRL) */
+#define DAT_RATE_CTRL_DRJW GENMASK(1, 0) /* Data field resync jump width */
+#define DAT_RATE_CTRL_DPRS GENMASK(4, 2) /* Data field propagation segment */
+#define DAT_RATE_CTRL_DPH1S GENMASK(7, 5) /* Data field phase1 segment */
+#define DAT_RATE_CTRL_DPH2S GENMASK(10, 8) /* Data field phase2 segment */
+#define DAT_RATE_CTRL_DPD GENMASK(28, 16) /* Data field prescaler divider */
+
+/* Acceptance identifierX register (ACC_IDX) */
+#define ACC_IDX_AID_MASK GENMASK(28, 0) /* Acceptance identifier */
+
+/* Acceptance identifier0 mask register (ACC_ID0_MASK) */
+#define ACC_IDX_MASK_AID_MASK GENMASK(28, 0) /* Acceptance identifier mask */
+
+/* Transfer status register (XFER_STS) */
+#define XFER_STS_FRAS GENMASK(2, 0) /* Frame status */
+#define XFER_STS_FIES GENMASK(7, 3) /* Field status */
+#define XFER_STS_FIES_IDLE (0x0) /* idle */
+#define XFER_STS_FIES_ARBITRATION (0x1) /* arbitration */
+#define XFER_STS_FIES_TX_CTRL (0x2) /* transmit control */
+#define XFER_STS_FIES_TX_DATA (0x3) /* transmit data */
+#define XFER_STS_FIES_TX_CRC (0x4) /* transmit crc */
+#define XFER_STS_FIES_TX_FRM (0x5) /* transmit frame */
+#define XFER_STS_FIES_RX_CTRL (0x6) /* receive control */
+#define XFER_STS_FIES_RX_DATA (0x7) /* receive data */
+#define XFER_STS_FIES_RX_CRC (0x8) /* receive crc */
+#define XFER_STS_FIES_RX_FRM (0x9) /* receive frame */
+#define XFER_STS_FIES_INTERMISSION (0xa) /* intermission */
+#define XFER_STS_FIES_TX_SUSPD (0xb) /* transmit suspend */
+#define XFER_STS_FIES_BUS_IDLE (0xc) /* bus idle */
+#define XFER_STS_FIES_OVL_FLAG (0xd) /* overload flag */
+#define XFER_STS_FIES_OVL_DLM (0xe) /* overload delimiter */
+#define XFER_STS_FIES_ERR_FLAG (0xf) /* error flag */
+#define XFER_STS_FIES_ERR_DLM (0x10) /* error delimiter */
+#define XFER_STS_FIES_BUS_OFF (0x11) /* bus off */
+#define XFER_STS_TS BIT(8) /* Transmit status */
+#define XFER_STS_RS BIT(9) /* Receive status */
+#define XFER_STS_XFERS BIT(10) /* Transfer status */
+
+/* Error counter register (ERR_CNT) */
+#define ERR_CNT_REC GENMASK(8, 0) /* Receive error counter */
+#define ERR_CNT_TEC GENMASK(24, 16) /* Transmit error counter */
+
+/* FIFO counter register (FIFO_CNT) */
+#define FIFO_CNT_RFN GENMASK(6, 0) /* Receive FIFO valid data number */
+#define FIFO_CNT_TFN GENMASK(22, 16) /* Transmit FIFO valid data number */
+
+/* DMA request control register (DMA_CTRL) */
+#define DMA_CTRL_RFTH GENMASK(5, 0) /* Receive FIFO DMA request threshold */
+#define DMA_CTRL_RFRE BIT(6) /* Receive FIFO DMA request enable */
+#define DMA_CTRL_TFTH GENMASK(21, 16) /* Transmit FIFO DMA request threshold */
+#define DMA_CTRL_TFRE BIT(22) /* Transmit FIFO DMA request enable */
+
+/* Transfer enable register (XFER_EN) */
+#define XFER_EN_XFER BIT(0) /* Transfer enable */
+
+/* Interrupt register 1 (INTR1) */
+#define INTR1_RF1IS BIT(0) /* RX FIFO 1/4 interrupt status */
+#define INTR1_RF2IS BIT(1) /* RX FIFO 1/2 interrupt status */
+#define INTR1_RF3IS BIT(2) /* RX FIFO 3/4 interrupt status */
+#define INTR1_RF4IS BIT(3) /* RX FIFO full interrupt status */
+#define INTR1_TF1IS BIT(4) /* TX FIFO 1/4 interrupt status */
+#define INTR1_TF2IS BIT(5) /* TX FIFO 1/2 interrupt status */
+#define INTR1_TF3IS BIT(6) /* TX FIFO 3/4 interrupt status */
+#define INTR1_TF4IS BIT(7) /* TX FIFO empty interrupt status */
+#define INTR1_RF1IE BIT(8) /* RX FIFO 1/4 interrupt enable */
+#define INTR1_RF2IE BIT(9) /* RX FIFO 1/2 interrupt enable */
+#define INTR1_RF3IE BIT(10) /* RX FIFO 3/4 interrupt enable */
+#define INTR1_RF4IE BIT(11) /* RX FIFO full interrupt enable */
+#define INTR1_TF1IE BIT(12) /* TX FIFO 1/4 interrupt enable */
+#define INTR1_TF2IE BIT(13) /* TX FIFO 1/2 interrupt enable */
+#define INTR1_TF3IE BIT(14) /* TX FIFO 3/4 interrupt enable */
+#define INTR1_TF4IE BIT(15) /* TX FIFO empty interrupt enable */
+#define INTR1_RF1IC BIT(16) /* RX FIFO 1/4 interrupt clear */
+#define INTR1_RF2IC BIT(17) /* RX FIFO 1/2 interrupt clear */
+#define INTR1_RF3IC BIT(18) /* RX FIFO 3/4 interrupt clear */
+#define INTR1_RF4IC BIT(19) /* RX FIFO full interrupt clear */
+#define INTR1_TF1IC BIT(20) /* TX FIFO 1/4 interrupt clear */
+#define INTR1_TF2IC BIT(21) /* TX FIFO 1/2 interrupt clear */
+#define INTR1_TF3IC BIT(22) /* TX FIFO 3/4 interrupt clear */
+#define INTR1_TF4IC BIT(23) /* TX FIFO empty interrupt clear */
+#define INTR1_RF1RIS BIT(24) /* RX FIFO 1/4 raw interrupt status */
+#define INTR1_RF2RIS BIT(25) /* RX FIFO 1/2 raw interrupt status */
+#define INTR1_RF3RIS BIT(26) /* RX FIFO 3/4 raw interrupt status */
+#define INTR1_RF4RIS BIT(27) /* RX FIFO full raw interrupt status */
+#define INTR1_TF1RIS BIT(28) /* TX FIFO 1/4 raw interrupt status */
+#define INTR1_TF2RIS BIT(29) /* TX FIFO 1/2 raw interrupt status */
+#define INTR1_TF3RIS BIT(30) /* TX FIFO 3/4 raw interrupt status */
+#define INTR1_TF4RIS BIT(31) /* TX FIFO empty raw interrupt status */
+
+/* Frame valid number register (FRM_INFO) */
+#define FRM_INFO_RXFC GENMASK(5, 0) /* Valid frame number in RX FIFO */
+#define FRM_INFO_SSPD GENMASK(31, 16) /* Secondary sample point delay */
+
+/* Interrupt register 2 (INTR2) */
+#define INTR2_TOIS BIT(0) /* RX FIFO time out interrupt status */
+#define INTR2_TOIM BIT(8) /* RX FIFO time out interrupt mask */
+#define INTR2_TOIC BIT(16) /* RX FIFO time out interrupt clear */
+#define INTR2_TORIS BIT(24) /* RX FIFO time out raw interrupt status */
+
+/* RX information FIFO shadow register (RX_INFO_FIFO) */
+#define RX_INFO_FIFO_WNORF GENMASK(4, 0) /* Word (4-byte) number of current receive frame */
+#define RX_INFO_FIFO_RORF BIT(5) /* RTR value of current receive frame */
+#define RX_INFO_FIFO_FORF BIT(6) /* FDF value of current receive frame */
+#define RX_INFO_FIFO_IORF BIT(7) /* IDE value of current receive frame */
+
+/* Arbitration Bits */
+#define CAN_ID1_MASK GENMASK(31, 21) /* Base identifer */
+/* Standard Remote Transmission Request */
+#define CAN_ID1_RTR_MASK BIT(20)
+/* Extended Substitute remote TXreq */
+#define CAN_ID2_SRR_MASK BIT(20)
+#define CAN_IDE_MASK BIT(19) /* IDentifier extension flag */
+#define CAN_ID2_MASK GENMASK(18, 1) /* Identifier extension */
+/* Extended frames remote TX request */
+#define CAN_ID2_RTR_MASK BIT(0)
+#define CAN_ID1_FDF_MASK BIT(18)
+#define CAN_ID1_DLC_MASK GENMASK(17, 14)
+#define CANFD_ID1_BRS_MASK BIT(16)
+#define CANFD_ID1_ESI_MASK BIT(15)
+#define CANFD_ID1_DLC_MASK GENMASK(14, 11)
+
+#define CAN_ID2_FDF_MASK BIT(31)
+#define CAN_ID2_DLC_MASK GENMASK(29, 26)
+#define CANFD_ID2_BRS_MASK BIT(29)
+#define CANFD_ID2_ESI_MASK BIT(28)
+#define CANFD_ID2_DLC_MASK GENMASK(27, 24)
+
+#define CAN_ID1_DLC_OFF 14
+#define CANFD_ID1_DLC_OFF 11
+#define CAN_ID2_DLC_OFF 26
+#define CANFD_ID2_DLC_OFF 24
+
+#define CAN_IDR_ID1_SHIFT 21 /* Standard Messg Identifier */
+#define CAN_IDR_ID2_SHIFT 1 /* Extended Message Identifier */
+#define CAN_IDR_SDLC_SHIFT 14
+#define CAN_IDR_EDLC_SHIFT 26
+
+/* CANFD Standard msg padding 1 */
+#define CANFD_IDR_PAD_MASK 0x000007FF
+#define CAN_IDR_PAD_MASK 0x00003FFF /* Standard msg padding 1 */
+
+/**
+ * phytium_can_set_reg_bits - set a bit value to the device register
+ * @cdev: Driver private data structure
+ * @reg: Register offset
+ * @bs: The bit mask
+ *
+ * Read data from the particular CAN register
+ * Return: value read from the CAN register
+ */
+static void
+phytium_can_set_reg_bits(const struct phytium_can_dev *cdev,
+ enum phytium_can_reg reg, u32 bs)
+{
+ u32 val = readl(cdev->base + reg);
+
+ val |= bs;
+ writel(val, cdev->base + reg);
+}
+
+/**
+ * phytium_can_clr_reg_bits - clear a bit value to the device register
+ * @cdev: Driver private data structure
+ * @reg: Register offset
+ * @bs: The bit mask
+ *
+ * Read data from the particular CAN register
+ * Return: value read from the CAN register
+ */
+static void
+phytium_can_clr_reg_bits(const struct phytium_can_dev *cdev,
+ enum phytium_can_reg reg, u32 bs)
+{
+ u32 val = readl(cdev->base + reg);
+
+ val &= ~bs;
+ writel(val, cdev->base + reg);
+}
+
+static inline u32 phytium_can_read(const struct phytium_can_dev *cdev, enum phytium_can_reg reg)
+{
+ return readl(cdev->base + reg);
+}
+
+static inline void phytium_can_write(const struct phytium_can_dev *cdev, enum phytium_can_reg reg,
+ u32 val)
+{
+ writel(val, cdev->base + reg);
+}
+
+static inline void phytium_can_enable_all_interrupts(struct phytium_can_dev *cdev)
+{
+ phytium_can_write(cdev, CAN_INTR, INTR_EN_MASK);
+}
+
+static inline void phytium_can_disable_all_interrupt(struct phytium_can_dev *cdev)
+{
+ phytium_can_write(cdev, CAN_INTR, 0x0);
+}
+
+static int phytium_can_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ struct phytium_can_dev *cdev = netdev_priv(dev);
+
+ bec->rxerr = phytium_can_read(cdev, CAN_ERROR_CNT) & ERR_CNT_REC;
+ bec->txerr = (phytium_can_read(cdev, CAN_ERROR_CNT) & ERR_CNT_TEC) >> 16;
+
+ return 0;
+}
+
+static int phytium_can_read_fifo(struct net_device *dev)
+{
+ struct net_device_stats *stats = &dev->stats;
+ struct phytium_can_dev *cdev = netdev_priv(dev);
+ struct canfd_frame *cf;
+ struct sk_buff *skb;
+ u32 id, dlc, i;
+
+ /* Read the frame header from FIFO */
+ id = phytium_can_read(cdev, CAN_RX_FIFO);
+ id = be32_to_cpup(&id);
+ if (id & CAN_IDE_MASK) {
+ /* Received an extended frame */
+ dlc = phytium_can_read(cdev, CAN_RX_FIFO);
+ dlc = be32_to_cpup(&dlc);
+ if (dlc & CAN_ID2_FDF_MASK)
+ skb = alloc_canfd_skb(dev, &cf);
+ else
+ skb = alloc_can_skb(dev, (struct can_frame **)&cf);
+
+ if (unlikely(!skb)) {
+ stats->rx_dropped++;
+ return 0;
+ }
+
+ if (dlc & CAN_ID2_FDF_MASK) {
+ /* CAN FD extended frame */
+ if (dlc & CANFD_ID2_BRS_MASK)
+ cf->flags |= CANFD_BRS;
+ if (dlc & CANFD_ID2_ESI_MASK)
+ cf->flags |= CANFD_ESI;
+ cf->len = can_fd_dlc2len((dlc & CANFD_ID2_DLC_MASK) >> CANFD_ID2_DLC_OFF);
+ } else {
+ /* CAN extended frame */
+ cf->len = can_cc_dlc2len((dlc & CAN_ID2_DLC_MASK) >> CAN_ID2_DLC_OFF);
+ }
+
+ cf->can_id = (id & CAN_ID1_MASK) >> 3;
+ cf->can_id |= (id & CAN_ID2_MASK) >> 1;
+ cf->can_id |= CAN_EFF_FLAG;
+
+ if (id & CAN_ID2_RTR_MASK)
+ cf->can_id |= CAN_RTR_FLAG;
+ } else {
+ /* Received a standard frame */
+ if (id & CAN_ID1_FDF_MASK)
+ skb = alloc_canfd_skb(dev, &cf);
+ else
+ skb = alloc_can_skb(dev, (struct can_frame **)&cf);
+
+ if (unlikely(!skb)) {
+ stats->rx_dropped++;
+ return 0;
+ }
+
+ if (id & CAN_ID1_FDF_MASK) {
+ /* CAN FD extended frame */
+ if (id & CANFD_ID1_BRS_MASK)
+ cf->flags |= CANFD_BRS;
+ if (id & CANFD_ID1_ESI_MASK)
+ cf->flags |= CANFD_ESI;
+ cf->len = can_fd_dlc2len((id & CANFD_ID1_DLC_MASK) >> CANFD_ID1_DLC_OFF);
+ } else {
+ /* CAN extended frame */
+ cf->len = can_cc_dlc2len((id & CAN_ID1_DLC_MASK) >> CAN_ID1_DLC_OFF);
+ }
+
+ cf->can_id = (id & CAN_ID1_MASK) >> 21;
+
+ if (id & CAN_ID1_RTR_MASK)
+ cf->can_id |= CAN_RTR_FLAG;
+ }
+
+ if (!(cf->can_id & CAN_RTR_FLAG))
+ /* Receive data frames */
+ for (i = 0; i < cf->len; i += 4)
+ *(__be32 *)(cf->data + i) = phytium_can_read(cdev, CAN_RX_FIFO);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->len;
+ netif_receive_skb(skb);
+
+ return 1;
+}
+
+static int phytium_can_do_rx_poll(struct net_device *dev, int quota)
+{
+ struct phytium_can_dev *cdev = netdev_priv(dev);
+ u32 rxfs, pkts = 0;
+ int isr;
+
+ isr = cdev->isr;
+
+ rxfs = phytium_can_read(cdev, CAN_FIFO_CNT) & FIFO_CNT_RFN;
+ if (!rxfs) {
+ netdev_dbg(dev, "no messages in RX FIFO\n");
+ return 0;
+ }
+
+ while ((rxfs != 0) && (quota > 0)) {
+ if (isr & INTR_REIS) {
+ pkts += phytium_can_read_fifo(dev);
+ quota--;
+ } else {
+ break;
+ }
+ rxfs = phytium_can_read(cdev, CAN_FIFO_CNT) & FIFO_CNT_RFN;
+ netdev_dbg(dev, "Next received %d frame again.\n", rxfs);
+ }
+
+ return pkts;
+}
+
+static int phytium_can_rx_handler(struct net_device *dev, int quota)
+{
+ struct phytium_can_dev *cdev = netdev_priv(dev);
+ int work_done = 0;
+ u32 isr;
+
+ isr = cdev->isr | phytium_can_read(cdev, CAN_INTR);
+ if (!isr)
+ goto end;
+
+ /* Handle RX IRQ */
+ if (isr & INTR_REIS) {
+ int rx_work_or_err;
+
+ rx_work_or_err = phytium_can_do_rx_poll(dev, (quota - work_done));
+ if (rx_work_or_err < 0)
+ return rx_work_or_err;
+
+ work_done += rx_work_or_err;
+ }
+
+end:
+ return 0;
+}
+
+static int phytium_can_poll(struct napi_struct *napi, int quota)
+{
+ struct net_device *dev = napi->dev;
+ struct phytium_can_dev *cdev = netdev_priv(dev);
+ int work_done;
+
+ netdev_dbg(dev, "The receive processing is going on !\n");
+
+ work_done = phytium_can_rx_handler(dev, quota);
+
+ /* Don't re-enable interrupts if the driver had a fatal error
+ * (e.g., FIFO read failure)
+ */
+ if (work_done >= 0 && work_done < quota) {
+ napi_complete_done(napi, work_done);
+ phytium_can_enable_all_interrupts(cdev);
+ }
+
+ return work_done;
+}
+
+static void phytium_can_write_frame(struct phytium_can_dev *cdev)
+{
+ struct canfd_frame *cf = (struct canfd_frame *)cdev->tx_skb->data;
+ struct net_device *dev = cdev->net;
+ struct sk_buff *skb = cdev->tx_skb;
+ u32 i, id, dlc = 0, frame_head[2] = {0, 0};
+ u32 data_len;
+
+ data_len = can_fd_len2dlc(cf->len);
+ cdev->tx_skb = NULL;
+
+ /* Watch carefully on the bit sequence */
+ if (cf->can_id & CAN_EFF_FLAG) {
+ /* Extended CAN ID format */
+ id = ((cf->can_id & CAN_EFF_MASK) << 1) & CAN_ID2_MASK;
+ id |= (((cf->can_id & CAN_EFF_MASK) >>
+ (CAN_EFF_ID_BITS - CAN_SFF_ID_BITS)) <<
+ CAN_IDR_ID1_SHIFT) & CAN_ID1_MASK;
+
+ /* The substibute remote TX request bit should be "1"
+ * for extended frames as in the Phytium CAN datasheet
+ */
+ id |= CAN_IDE_MASK | CAN_ID2_SRR_MASK;
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ /* Extended frames remote TX request */
+ id |= CAN_ID2_RTR_MASK;
+ if ((cdev->can.ctrlmode & CAN_CTRLMODE_FD) &&
+ can_is_canfd_skb(skb))
+ dlc = data_len << CANFD_ID2_DLC_OFF;
+ else
+ dlc = data_len << CAN_ID2_DLC_OFF;
+
+ if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
+ dlc |= CAN_ID2_FDF_MASK;
+ if (cf->flags & CANFD_BRS)
+ dlc |= CANFD_ID2_BRS_MASK;
+ if (cf->flags & CANFD_ESI)
+ dlc |= CANFD_ID2_ESI_MASK;
+ }
+
+ frame_head[0] = cpu_to_be32p(&id);
+ frame_head[1] = cpu_to_be32p(&dlc);
+
+ /* Write the Frame to Phytium CAN TX FIFO */
+ phytium_can_write(cdev, CAN_TX_FIFO, frame_head[0]);
+ phytium_can_write(cdev, CAN_TX_FIFO, frame_head[1]);
+ netdev_dbg(dev, "Write atbitration field [0]:0x%x [1]:0x%x\n",
+ frame_head[0], frame_head[1]);
+ } else {
+ /* Standard CAN ID format */
+ id = ((cf->can_id & CAN_SFF_MASK) << CAN_IDR_ID1_SHIFT)
+ & CAN_ID1_MASK;
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ /* Standard frames remote TX request */
+ id |= CAN_ID1_RTR_MASK;
+
+ if (cdev->can.ctrlmode & CAN_CTRLMODE_FD)
+ dlc = (data_len << CANFD_ID1_DLC_OFF)
+ | CANFD_IDR_PAD_MASK;
+ else
+ dlc = (data_len << CAN_ID1_DLC_OFF) | CAN_IDR_PAD_MASK;
+
+ id |= dlc;
+
+ if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
+ id |= CAN_ID1_FDF_MASK;
+ if (cf->flags & CANFD_BRS)
+ id |= CANFD_ID1_BRS_MASK;
+ if (cf->flags & CANFD_ESI)
+ id |= CANFD_ID1_ESI_MASK;
+ }
+
+ frame_head[0] = cpu_to_be32p(&id);
+ /* Write the Frame to Phytium CAN TX FIFO */
+ phytium_can_write(cdev, CAN_TX_FIFO, frame_head[0]);
+ netdev_dbg(dev, "Write atbitration field [0] 0x%x\n",
+ frame_head[0]);
+ }
+
+ if (!(cf->can_id & CAN_RTR_FLAG)) {
+ netdev_dbg(dev, "Write CAN data frame\n");
+ for (i = 0; i < cf->len; i += 4) {
+ phytium_can_write(cdev, CAN_TX_FIFO,
+ *(__be32 *)(cf->data + i));
+ netdev_dbg(dev, "[%d]:%x\n", i,
+ *(__be32 *)(cf->data + i));
+ }
+ }
+
+ can_put_echo_skb(skb, dev, cdev->tx_head % cdev->tx_max, 0);
+ cdev->tx_head++;
+
+ netif_stop_queue(dev);
+ /* trigger transmission */
+ phytium_can_clr_reg_bits(cdev, CAN_CTRL, CTRL_XFER);
+ phytium_can_set_reg_bits(cdev, CAN_CTRL, CTRL_TXREQ | CTRL_XFER);
+
+ netdev_dbg(dev, "Trigger send message!\n");
+}
+
+static netdev_tx_t phytium_can_tx_handler(struct phytium_can_dev *cdev)
+{
+ struct net_device *dev = cdev->net;
+ u32 tx_fifo_used;
+
+ /* Check if the TX buffer is full */
+ tx_fifo_used = (phytium_can_read(cdev, CAN_FIFO_CNT) & FIFO_CNT_TFN) >> 16;
+ if (tx_fifo_used == cdev->tx_max) {
+ netif_stop_queue(dev);
+ netdev_err(dev, "BUG!, TX FIFO full when queue awake!\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ if (cdev->tx_head == cdev->tx_tail) {
+ cdev->tx_head = 0;
+ cdev->tx_tail = 0;
+ }
+
+ phytium_can_write_frame(cdev);
+
+ return NETDEV_TX_OK;
+}
+
+/**
+ * phytium_can_tx_interrupt - Tx Done Isr
+ * @ndev: net_device pointer
+ * @isr: Interrupt status register value
+ */
+static void phytium_can_tx_interrupt(struct net_device *ndev, u32 isr)
+{
+ struct phytium_can_dev *cdev = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+
+ while ((cdev->tx_head - cdev->tx_tail > 0) && (isr & INTR_TEIS)) {
+ phytium_can_set_reg_bits(cdev, CAN_INTR, INTR_TEIC | INTR_REIC);
+ stats->tx_bytes = can_get_echo_skb(ndev, cdev->tx_tail % cdev->tx_max, NULL);
+ cdev->tx_tail++;
+ stats->tx_packets++;
+ isr = (phytium_can_read(cdev, CAN_INTR) & INTR_STATUS_MASK);
+ }
+
+ phytium_can_clr_reg_bits(cdev, CAN_CTRL, CTRL_XFER);
+ phytium_can_clr_reg_bits(cdev, CAN_CTRL, CTRL_TXREQ);
+ phytium_can_set_reg_bits(cdev, CAN_CTRL, CTRL_XFER);
+ netdev_dbg(ndev, "Finish transform packets %lu\n", stats->tx_packets);
+ netdev_dbg(ndev, "\n-------------------\n");
+ netif_wake_queue(ndev);
+}
+
+static void phytium_can_err_interrupt(struct net_device *ndev, u32 isr)
+{
+ struct phytium_can_dev *cdev = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ u32 txerr = 0, rxerr = 0;
+
+ skb = alloc_can_err_skb(ndev, &cf);
+
+ rxerr = phytium_can_read(cdev, CAN_ERROR_CNT) & ERR_CNT_REC;
+ txerr = ((phytium_can_read(cdev, CAN_ERROR_CNT) & ERR_CNT_TEC) >> 16);
+
+ if (isr & INTR_BOIS) {
+ netdev_dbg(ndev, "%s: txerr :%u rxerr :%u\n",
+ __func__, txerr, rxerr);
+ cdev->can.state = CAN_STATE_BUS_OFF;
+ cdev->can.can_stats.bus_off++;
+ /* Leave device in Config Mode in bus-off state */
+ phytium_can_write(cdev, CAN_CTRL, CTRL_RST);
+ can_bus_off(ndev);
+ if (skb)
+ cf->can_id |= CAN_ERR_BUSOFF;
+ } else if ((isr & INTR_PEIS) == INTR_PEIS) {
+ netdev_dbg(ndev, "%s: txerr :%u rxerr :%u\n",
+ __func__, txerr, rxerr);
+ cdev->can.state = CAN_STATE_ERROR_PASSIVE;
+ cdev->can.can_stats.error_passive++;
+ if (skb) {
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = (rxerr > 127) ?
+ CAN_ERR_CRTL_RX_PASSIVE :
+ CAN_ERR_CRTL_TX_PASSIVE;
+ cf->data[6] = txerr;
+ cf->data[7] = rxerr;
+ }
+ } else if (isr & INTR_PWIS) {
+ netdev_dbg(ndev, "%s: txerr :%u rxerr :%u\n",
+ __func__, txerr, rxerr);
+ cdev->can.state = CAN_STATE_ERROR_WARNING;
+ cdev->can.can_stats.error_warning++;
+ if (skb) {
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= (txerr > rxerr) ?
+ CAN_ERR_CRTL_TX_WARNING :
+ CAN_ERR_CRTL_RX_WARNING;
+ cf->data[6] = txerr;
+ cf->data[7] = rxerr;
+ }
+ }
+
+ /* Check for RX FIFO Overflow interrupt */
+ if (isr & INTR_RFIS) {
+ stats->rx_over_errors++;
+ stats->rx_errors++;
+
+ if (skb) {
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
+ }
+ }
+
+ if (skb) {
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ netif_rx(skb);
+ }
+}
+
+/**
+ * phytium_can_isr - CAN Isr
+ * @irq: irq number
+ * @dev_id: device id poniter
+ *
+ * This is the phytium CAN Isr. It checks for the type of interrupt
+ * and invokes the corresponding ISR.
+ *
+ * Return:
+ * * IRQ_NONE - If CAN device is in sleep mode, IRQ_HANDLED otherwise
+ */
+static irqreturn_t phytium_can_isr(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct phytium_can_dev *cdev = netdev_priv(dev);
+ u32 isr;
+
+ /* Get the interrupt status */
+ isr = phytium_can_read(cdev, CAN_INTR) & INTR_STATUS_MASK;
+ if (!isr)
+ return IRQ_NONE;
+
+ /* Check for FIFO full interrupt and alarm */
+ if ((isr & INTR_RFIS)) {
+ netdev_dbg(dev, "rx_fifo is full!.\n");
+ isr &= (~INTR_RFIS);
+ phytium_can_clr_reg_bits(cdev, CAN_INTR, INTR_RFIE);
+ phytium_can_set_reg_bits(cdev, CAN_INTR, INTR_RFIC);
+ napi_schedule(&cdev->napi);
+ }
+
+ /* Check for the type of error interrupt and Processing it */
+ if (isr & (INTR_EIS | INTR_RFIS | INTR_BOIS | INTR_PEIS)) {
+ phytium_can_clr_reg_bits(cdev, CAN_INTR, (INTR_EIE
+ | INTR_RFIE | INTR_BOIE | INTR_PEIE));
+ phytium_can_err_interrupt(dev, isr);
+ phytium_can_set_reg_bits(cdev, CAN_INTR, (INTR_EIC
+ | INTR_RFIC | INTR_BOIC | INTR_PEIC));
+ phytium_can_set_reg_bits(cdev, CAN_INTR, INTR_EN_MASK);
+ return IRQ_HANDLED;
+ }
+
+ /* Check for Tx interrupt and Processing it */
+ if ((isr & INTR_TEIS)) {
+ isr &= (~INTR_REIS);
+ phytium_can_tx_interrupt(dev, isr);
+ }
+
+ /* Check for the type of receive interrupt and Processing it */
+ if (isr & (INTR_REIS)) {
+ cdev->isr = (isr & INTR_REIS);
+ phytium_can_clr_reg_bits(cdev, CAN_INTR, INTR_REIE);
+ phytium_can_set_reg_bits(cdev, CAN_INTR, INTR_REIC);
+ napi_schedule(&cdev->napi);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * phytium_can_set_bittiming - CAN set bit timing routine
+ * @dev: Pointer to net_device structure
+ *
+ * This is the driver set bittiming routine.
+ * Return: 0 on success and failure value on error
+ */
+static int phytium_can_set_bittiming(struct net_device *dev)
+{
+ struct phytium_can_dev *cdev = netdev_priv(dev);
+ const struct can_bittiming *bt = &cdev->can.bittiming;
+ const struct can_bittiming *dbt = &cdev->can.data_bittiming;
+ u32 btr, dbtr;
+ u32 is_config_mode;
+
+ /**
+ * Check whether Phytium CAN is in configuration mode.
+ * It cannot set bit timing if Phytium CAN is not in configuration mode.
+ */
+ is_config_mode = phytium_can_read(cdev, CAN_CTRL) & CTRL_XFER;
+ if (is_config_mode) {
+ netdev_alert(dev, "BUG! Cannot set bittiming - CAN is not in config mode\n");
+ return -EPERM;
+ }
+
+ /* Setting Baud Rate prescalar value in BRPR Register */
+ btr = (bt->brp - 1) << 16;
+
+ /* Setting Time Segment 1 in BTR Register */
+ btr |= (bt->prop_seg - 1) << 2;
+
+ btr |= (bt->phase_seg1 - 1) << 5;
+
+ /* Setting Time Segment 2 in BTR Register */
+ btr |= (bt->phase_seg2 - 1) << 8;
+
+ /* Setting Synchronous jump width in BTR Register */
+ btr |= (bt->sjw - 1);
+
+ dbtr = (dbt->brp - 1) << 16;
+ dbtr |= (dbt->prop_seg - 1) << 2;
+ dbtr |= (dbt->phase_seg1 - 1) << 5;
+ dbtr |= (dbt->phase_seg2 - 1) << 8;
+ dbtr |= (dbt->sjw - 1);
+
+ if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
+ phytium_can_write(cdev, CAN_ARB_RATE_CTRL, btr);
+ phytium_can_write(cdev, CAN_DAT_RATE_CTRL, dbtr);
+ } else {
+ phytium_can_write(cdev, CAN_ARB_RATE_CTRL, btr);
+ phytium_can_write(cdev, CAN_DAT_RATE_CTRL, btr);
+ }
+
+ netdev_dbg(dev, "DAT=0x%08x, ARB=0x%08x\n",
+ phytium_can_read(cdev, CAN_DAT_RATE_CTRL),
+ phytium_can_read(cdev, CAN_ARB_RATE_CTRL));
+
+ return 0;
+}
+
+/**
+ * phytium_can_start - This the drivers start routine
+ * @dev: Pointer to net_device structure
+ *
+ * This is the drivers start routine.
+ * Based on the State of the CAN device it puts
+ * the CAN device into a proper mode.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static void phytium_can_start(struct net_device *dev)
+{
+ struct phytium_can_dev *cdev = netdev_priv(dev);
+ u32 ctrl;
+
+ /* Disable transfer */
+ ctrl = phytium_can_read(cdev, CAN_CTRL);
+ ctrl &= ~CTRL_XFER;
+ phytium_can_write(cdev, CAN_CTRL, ctrl);
+
+ /* XXX: If CANFD, reset the controller */
+ phytium_can_write(cdev, CAN_CTRL, (ctrl | CTRL_RST));
+
+ /* Bittiming setup */
+ phytium_can_set_bittiming(dev);
+
+ /* Acceptance identifier mask setup */
+ phytium_can_write(cdev, CAN_ACC_ID0_MASK, ACC_IDX_MASK_AID_MASK);
+ phytium_can_write(cdev, CAN_ACC_ID1_MASK, ACC_IDX_MASK_AID_MASK);
+ phytium_can_write(cdev, CAN_ACC_ID2_MASK, ACC_IDX_MASK_AID_MASK);
+ phytium_can_write(cdev, CAN_ACC_ID3_MASK, ACC_IDX_MASK_AID_MASK);
+ ctrl |= CTRL_AIME;
+
+ if (cdev->can.ctrlmode & CAN_CTRLMODE_FD)
+ ctrl |= CTRL_IOF | CTRL_FDCRC;
+
+ phytium_can_write(cdev, CAN_CTRL, ctrl);
+
+ cdev->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ phytium_can_enable_all_interrupts(cdev);
+
+ if (cdev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ ctrl |= CTRL_XFER;
+ else
+ ctrl |= CTRL_XFER | CTRL_TXREQ;
+
+ phytium_can_write(cdev, CAN_CTRL, ctrl);
+}
+
+/**
+ * phytium_can_stop - Driver stop routine
+ * @dev: Pointer to net_device structure
+ *
+ * This is the drivers stop routine. It will disable the
+ * interrupts and put the device into configuration mode.
+ */
+static void phytium_can_stop(struct net_device *dev)
+{
+ struct phytium_can_dev *cdev = netdev_priv(dev);
+ u32 ctrl;
+
+ /* Disable all interrupts */
+ phytium_can_disable_all_interrupt(cdev);