/
xilinx-csi2rxss.c
2133 lines (1837 loc) · 60 KB
/
xilinx-csi2rxss.c
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
/*
* Xilinx MIPI CSI2 Subsystem
*
* Copyright (C) 2016 Xilinx, Inc.
*
* Contacts: Vishal Sagar <vsagar@xilinx.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <dt-bindings/media/xilinx-vip.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/spinlock_types.h>
#include <linux/types.h>
#include <linux/v4l2-subdev.h>
#include <linux/xilinx-csi2rxss.h>
#include <linux/xilinx-v4l2-controls.h>
#include <media/media-entity.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#include "xilinx-vip.h"
/*
* MIPI CSI2 Rx register map, bitmask and offsets
*/
#define XCSI_CCR_OFFSET 0x00000000
#define XCSI_CCR_SOFTRESET_SHIFT 1
#define XCSI_CCR_COREENB_SHIFT 0
#define XCSI_CCR_SOFTRESET_MASK BIT(XCSI_CCR_SOFTRESET_SHIFT)
#define XCSI_CCR_COREENB_MASK BIT(XCSI_CCR_COREENB_SHIFT)
#define XCSI_PCR_OFFSET 0x00000004
#define XCSI_PCR_MAXLANES_MASK 0x00000018
#define XCSI_PCR_ACTLANES_MASK 0x00000003
#define XCSI_PCR_MAXLANES_SHIFT 3
#define XCSI_PCR_ACTLANES_SHIFT 0
#define XCSI_CSR_OFFSET 0x00000010
#define XCSI_CSR_PKTCOUNT_SHIFT 16
#define XCSI_CSR_SPFIFOFULL_SHIFT 3
#define XCSI_CSR_SPFIFONE_SHIFT 2
#define XCSI_CSR_SLBF_SHIFT 1
#define XCSI_CSR_RIPCD_SHIFT 0
#define XCSI_CSR_PKTCOUNT_MASK 0xFFFF0000
#define XCSI_CSR_SPFIFOFULL_MASK BIT(XCSI_CSR_SPFIFOFULL_SHIFT)
#define XCSI_CSR_SPFIFONE_MASK BIT(XCSI_CSR_SPFIFONE_SHIFT)
#define XCSI_CSR_SLBF_MASK BIT(XCSI_CSR_SLBF_SHIFT)
#define XCSI_CSR_RIPCD_MASK BIT(XCSI_CSR_RIPCD_SHIFT)
#define XCSI_GIER_OFFSET 0x00000020
#define XCSI_GIER_GIE_SHIFT 0
#define XCSI_GIER_GIE_MASK BIT(XCSI_GIER_GIE_SHIFT)
#define XCSI_GIER_SET 1
#define XCSI_GIER_RESET 0
#define XCSI_ISR_OFFSET 0x00000024
#define XCSI_ISR_FR_SHIFT 31
#define XCSI_ISR_VCX_SHIFT 30
#define XCSI_ISR_YUV420_SHIFT 28
#define XCSI_ISR_ILC_SHIFT 21
#define XCSI_ISR_SPFIFOF_SHIFT 20
#define XCSI_ISR_SPFIFONE_SHIFT 19
#define XCSI_ISR_SLBF_SHIFT 18
#define XCSI_ISR_STOP_SHIFT 17
#define XCSI_ISR_SOTERR_SHIFT 13
#define XCSI_ISR_SOTSYNCERR_SHIFT 12
#define XCSI_ISR_ECC2BERR_SHIFT 11
#define XCSI_ISR_ECC1BERR_SHIFT 10
#define XCSI_ISR_CRCERR_SHIFT 9
#define XCSI_ISR_DATAIDERR_SHIFT 8
#define XCSI_ISR_VC3FSYNCERR_SHIFT 7
#define XCSI_ISR_VC3FLVLERR_SHIFT 6
#define XCSI_ISR_VC2FSYNCERR_SHIFT 5
#define XCSI_ISR_VC2FLVLERR_SHIFT 4
#define XCSI_ISR_VC1FSYNCERR_SHIFT 3
#define XCSI_ISR_VC1FLVLERR_SHIFT 2
#define XCSI_ISR_VC0FSYNCERR_SHIFT 1
#define XCSI_ISR_VC0FLVLERR_SHIFT 0
#define XCSI_ISR_FR_MASK BIT(XCSI_ISR_FR_SHIFT)
#define XCSI_ISR_VCX_MASK BIT(XCSI_ISR_VCX_SHIFT)
#define XCSI_ISR_YUV420_MASK BIT(XCSI_ISR_YUV420_SHIFT)
#define XCSI_ISR_ILC_MASK BIT(XCSI_ISR_ILC_SHIFT)
#define XCSI_ISR_SPFIFOF_MASK BIT(XCSI_ISR_SPFIFOF_SHIFT)
#define XCSI_ISR_SPFIFONE_MASK BIT(XCSI_ISR_SPFIFONE_SHIFT)
#define XCSI_ISR_SLBF_MASK BIT(XCSI_ISR_SLBF_SHIFT)
#define XCSI_ISR_STOP_MASK BIT(XCSI_ISR_STOP_SHIFT)
#define XCSI_ISR_SOTERR_MASK BIT(XCSI_ISR_SOTERR_SHIFT)
#define XCSI_ISR_SOTSYNCERR_MASK BIT(XCSI_ISR_SOTSYNCERR_SHIFT)
#define XCSI_ISR_ECC2BERR_MASK BIT(XCSI_ISR_ECC2BERR_SHIFT)
#define XCSI_ISR_ECC1BERR_MASK BIT(XCSI_ISR_ECC1BERR_SHIFT)
#define XCSI_ISR_CRCERR_MASK BIT(XCSI_ISR_CRCERR_SHIFT)
#define XCSI_ISR_DATAIDERR_MASK BIT(XCSI_ISR_DATAIDERR_SHIFT)
#define XCSI_ISR_VC3FSYNCERR_MASK BIT(XCSI_ISR_VC3FSYNCERR_SHIFT)
#define XCSI_ISR_VC3FLVLERR_MASK BIT(XCSI_ISR_VC3FLVLERR_SHIFT)
#define XCSI_ISR_VC2FSYNCERR_MASK BIT(XCSI_ISR_VC2FSYNCERR_SHIFT)
#define XCSI_ISR_VC2FLVLERR_MASK BIT(XCSI_ISR_VC2FLVLERR_SHIFT)
#define XCSI_ISR_VC1FSYNCERR_MASK BIT(XCSI_ISR_VC1FSYNCERR_SHIFT)
#define XCSI_ISR_VC1FLVLERR_MASK BIT(XCSI_ISR_VC1FLVLERR_SHIFT)
#define XCSI_ISR_VC0FSYNCERR_MASK BIT(XCSI_ISR_VC0FSYNCERR_SHIFT)
#define XCSI_ISR_VC0FLVLERR_MASK BIT(XCSI_ISR_VC0FLVLERR_SHIFT)
#define XCSI_ISR_ALLINTR_MASK 0xD03FFFFF
#define XCSI_INTR_PROT_MASK (XCSI_ISR_VC3FSYNCERR_MASK | \
XCSI_ISR_VC3FLVLERR_MASK | \
XCSI_ISR_VC2FSYNCERR_MASK | \
XCSI_ISR_VC2FLVLERR_MASK | \
XCSI_ISR_VC1FSYNCERR_MASK | \
XCSI_ISR_VC1FLVLERR_MASK | \
XCSI_ISR_VC0FSYNCERR_MASK | \
XCSI_ISR_VC0FLVLERR_MASK | \
XCSI_ISR_VCX_MASK)
#define XCSI_INTR_PKTLVL_MASK (XCSI_ISR_ECC2BERR_MASK | \
XCSI_ISR_ECC1BERR_MASK | \
XCSI_ISR_CRCERR_MASK | \
XCSI_ISR_DATAIDERR_MASK)
#define XCSI_INTR_DPHY_MASK (XCSI_ISR_SOTERR_MASK | \
XCSI_ISR_SOTSYNCERR_MASK)
#define XCSI_INTR_SPKT_MASK (XCSI_ISR_SPFIFOF_MASK | \
XCSI_ISR_SPFIFONE_MASK)
#define XCSI_INTR_FRAMERCVD_MASK (XCSI_ISR_FR_MASK)
#define XCSI_INTR_ERR_MASK (XCSI_ISR_ILC_MASK | \
XCSI_ISR_YUV420_MASK | \
XCSI_ISR_SLBF_MASK | \
XCSI_ISR_STOP_MASK)
#define XCSI_IER_OFFSET 0x00000028
#define XCSI_IER_FR_SHIFT 31
#define XCSI_IER_VCX_SHIFT 30
#define XCSI_IER_YUV420_SHIFT 28
#define XCSI_IER_ILC_SHIFT 21
#define XCSI_IER_SPFIFOF_SHIFT 20
#define XCSI_IER_SPFIFONE_SHIFT 19
#define XCSI_IER_SLBF_SHIFT 18
#define XCSI_IER_STOP_SHIFT 17
#define XCSI_IER_SOTERR_SHIFT 13
#define XCSI_IER_SOTSYNCERR_SHIFT 12
#define XCSI_IER_ECC2BERR_SHIFT 11
#define XCSI_IER_ECC1BERR_SHIFT 10
#define XCSI_IER_CRCERR_SHIFT 9
#define XCSI_IER_DATAIDERR_SHIFT 8
#define XCSI_IER_VC3FSYNCERR_SHIFT 7
#define XCSI_IER_VC3FLVLERR_SHIFT 6
#define XCSI_IER_VC2FSYNCERR_SHIFT 5
#define XCSI_IER_VC2FLVLERR_SHIFT 4
#define XCSI_IER_VC1FSYNCERR_SHIFT 3
#define XCSI_IER_VC1FLVLERR_SHIFT 2
#define XCSI_IER_VC0FSYNCERR_SHIFT 1
#define XCSI_IER_VC0FLVLERR_SHIFT 0
#define XCSI_IER_FR_MASK BIT(XCSI_IER_FR_SHIFT)
#define XCSI_IER_VCX_MASK BIT(XCSI_IER_VCX_SHIFT)
#define XCSI_IER_YUV420_MASK BIT(XCSI_IER_YUV420_SHIFT)
#define XCSI_IER_ILC_MASK BIT(XCSI_IER_ILC_SHIFT)
#define XCSI_IER_SPFIFOF_MASK BIT(XCSI_IER_SPFIFOF_SHIFT)
#define XCSI_IER_SPFIFONE_MASK BIT(XCSI_IER_SPFIFONE_SHIFT)
#define XCSI_IER_SLBF_MASK BIT(XCSI_IER_SLBF_SHIFT)
#define XCSI_IER_STOP_MASK BIT(XCSI_IER_STOP_SHIFT)
#define XCSI_IER_SOTERR_MASK BIT(XCSI_IER_SOTERR_SHIFT)
#define XCSI_IER_SOTSYNCERR_MASK BIT(XCSI_IER_SOTSYNCERR_SHIFT)
#define XCSI_IER_ECC2BERR_MASK BIT(XCSI_IER_ECC2BERR_SHIFT)
#define XCSI_IER_ECC1BERR_MASK BIT(XCSI_IER_ECC1BERR_SHIFT)
#define XCSI_IER_CRCERR_MASK BIT(XCSI_IER_CRCERR_SHIFT)
#define XCSI_IER_DATAIDERR_MASK BIT(XCSI_IER_DATAIDERR_SHIFT)
#define XCSI_IER_VC3FSYNCERR_MASK BIT(XCSI_IER_VC3FSYNCERR_SHIFT)
#define XCSI_IER_VC3FLVLERR_MASK BIT(XCSI_IER_VC3FLVLERR_SHIFT)
#define XCSI_IER_VC2FSYNCERR_MASK BIT(XCSI_IER_VC2FSYNCERR_SHIFT)
#define XCSI_IER_VC2FLVLERR_MASK BIT(XCSI_IER_VC2FLVLERR_SHIFT)
#define XCSI_IER_VC1FSYNCERR_MASK BIT(XCSI_IER_VC1FSYNCERR_SHIFT)
#define XCSI_IER_VC1FLVLERR_MASK BIT(XCSI_IER_VC1FLVLERR_SHIFT)
#define XCSI_IER_VC0FSYNCERR_MASK BIT(XCSI_IER_VC0FSYNCERR_SHIFT)
#define XCSI_IER_VC0FLVLERR_MASK BIT(XCSI_IER_VC0FLVLERR_SHIFT)
#define XCSI_IER_ALLINTR_MASK 0xD03FFFFF
#define XCSI_SPKTR_OFFSET 0x00000030
#define XCSI_SPKTR_DATA_SHIFT 8
#define XCSI_SPKTR_VC_SHIFT 6
#define XCSI_SPKTR_DT_SHIFT 0
#define XCSI_SPKTR_DATA_MASK 0x00FFFF00
#define XCSI_SPKTR_VC_MASK 0x000000C0
#define XCSI_SPKTR_DT_MASK 0x0000003F
#define XCSI_VCXR_OFFSET 0x00000034
#define XCSI_VCXR_VC15FSYNCERR_MASK BIT(23)
#define XCSI_VCXR_VC15FLVLERR_MASK BIT(22)
#define XCSI_VCXR_VC14FSYNCERR_MASK BIT(21)
#define XCSI_VCXR_VC14FLVLERR_MASK BIT(20)
#define XCSI_VCXR_VC13FSYNCERR_MASK BIT(19)
#define XCSI_VCXR_VC13FLVLERR_MASK BIT(18)
#define XCSI_VCXR_VC12FSYNCERR_MASK BIT(17)
#define XCSI_VCXR_VC12FLVLERR_MASK BIT(16)
#define XCSI_VCXR_VC11FSYNCERR_MASK BIT(15)
#define XCSI_VCXR_VC11FLVLERR_MASK BIT(14)
#define XCSI_VCXR_VC10FSYNCERR_MASK BIT(13)
#define XCSI_VCXR_VC10FLVLERR_MASK BIT(12)
#define XCSI_VCXR_VC9FSYNCERR_MASK BIT(11)
#define XCSI_VCXR_VC9FLVLERR_MASK BIT(10)
#define XCSI_VCXR_VC8FSYNCERR_MASK BIT(9)
#define XCSI_VCXR_VC8FLVLERR_MASK BIT(8)
#define XCSI_VCXR_VC7FSYNCERR_MASK BIT(7)
#define XCSI_VCXR_VC7FLVLERR_MASK BIT(6)
#define XCSI_VCXR_VC6FSYNCERR_MASK BIT(5)
#define XCSI_VCXR_VC6FLVLERR_MASK BIT(4)
#define XCSI_VCXR_VC5FSYNCERR_MASK BIT(3)
#define XCSI_VCXR_VC5FLVLERR_MASK BIT(2)
#define XCSI_VCXR_VC4FSYNCERR_MASK BIT(1)
#define XCSI_VCXR_VC4FLVLERR_MASK BIT(0)
#define XCSI_VCXR_MASK 0x00FFFFFF
#define XCSI_CLKINFR_OFFSET 0x0000003C
#define XCSI_CLKINFR_STOP_SHIFT 1
#define XCSI_CLKINFR_STOP_MASK BIT(XCSI_CLKINFR_STOP_SHIFT)
#define XCSI_L0INFR_OFFSET 0x00000040
#define XCSI_L1INFR_OFFSET 0x00000044
#define XCSI_L2INFR_OFFSET 0x00000048
#define XCSI_L3INFR_OFFSET 0x0000004C
#define XCSI_LXINFR_STOP_SHIFT 5
#define XCSI_LXINFR_SOTERR_SHIFT 1
#define XCSI_LXINFR_SOTSYNCERR_SHIFT 0
#define XCSI_LXINFR_STOP_MASK BIT(XCSI_LXINFR_STOP_SHIFT)
#define XCSI_LXINFR_SOTERR_MASK BIT(XCSI_LXINFR_SOTERR_SHIFT)
#define XCSI_LXINFR_SOTSYNCERR_MASK BIT(XCSI_LXINFR_SOTSYNCERR_SHIFT)
#define XCSI_VC0INF1R_OFFSET 0x00000060
#define XCSI_VC1INF1R_OFFSET 0x00000068
#define XCSI_VC2INF1R_OFFSET 0x00000070
#define XCSI_VC3INF1R_OFFSET 0x00000078
#define XCSI_VC4INF1R_OFFSET 0x00000080
#define XCSI_VC5INF1R_OFFSET 0x00000088
#define XCSI_VC6INF1R_OFFSET 0x00000090
#define XCSI_VC7INF1R_OFFSET 0x00000098
#define XCSI_VC8INF1R_OFFSET 0x000000A0
#define XCSI_VC9INF1R_OFFSET 0x000000A8
#define XCSI_VC10INF1R_OFFSET 0x000000B0
#define XCSI_VC11INF1R_OFFSET 0x000000B8
#define XCSI_VC12INF1R_OFFSET 0x000000C0
#define XCSI_VC13INF1R_OFFSET 0x000000C8
#define XCSI_VC14INF1R_OFFSET 0x000000D0
#define XCSI_VC15INF1R_OFFSET 0x000000D8
#define XCSI_VCXINF1R_LINECOUNT_SHIFT 16
#define XCSI_VCXINF1R_BYTECOUNT_SHIFT 0
#define XCSI_VCXINF1R_LINECOUNT_MASK 0xFFFF0000
#define XCSI_VCXINF1R_BYTECOUNT_MASK 0x0000FFFF
#define XCSI_VC0INF2R_OFFSET 0x00000064
#define XCSI_VC1INF2R_OFFSET 0x0000006C
#define XCSI_VC2INF2R_OFFSET 0x00000074
#define XCSI_VC3INF2R_OFFSET 0x0000007C
#define XCSI_VC4INF2R_OFFSET 0x00000084
#define XCSI_VC5INF2R_OFFSET 0x0000008C
#define XCSI_VC6INF2R_OFFSET 0x00000094
#define XCSI_VC7INF2R_OFFSET 0x0000009C
#define XCSI_VC8INF2R_OFFSET 0x000000A4
#define XCSI_VC9INF2R_OFFSET 0x000000AC
#define XCSI_VC10INF2R_OFFSET 0x000000B4
#define XCSI_VC11INF2R_OFFSET 0x000000BC
#define XCSI_VC12INF2R_OFFSET 0x000000C4
#define XCSI_VC13INF2R_OFFSET 0x000000CC
#define XCSI_VC14INF2R_OFFSET 0x000000D4
#define XCSI_VC15INF2R_OFFSET 0x000000DC
#define XCSI_VCXINF2R_DATATYPE_SHIFT 0
#define XCSI_VCXINF2R_DATATYPE_MASK 0x0000003F
#define XDPHY_CTRLREG_OFFSET 0x0
#define XDPHY_CTRLREG_DPHYEN_SHIFT 1
#define XDPHY_CTRLREG_DPHYEN_MASK BIT(XDPHY_CTRLREG_DPHYEN_SHIFT)
#define XDPHY_CLKSTATREG_OFFSET 0x18
#define XDPHY_CLKSTATREG_MODE_SHIFT 0
#define XDPHY_CLKSTATREG_MODE_MASK 0x3
#define XDPHY_LOW_POWER_MODE 0x0
#define XDPHY_HI_SPEED_MODE 0x1
#define XDPHY_ESC_MODE 0x2
/*
* Interrupt mask
*/
#define XCSI_INTR_MASK (XCSI_ISR_ALLINTR_MASK & ~XCSI_ISR_STOP_MASK)
/*
* Timeout for reset
*/
#define XCSI_TIMEOUT_VAL (1000) /* us */
/*
* Max string length for CSI Data type string
*/
#define MAX_XIL_CSIDT_STR_LENGTH 64
/*
* Maximum number of short packet events per file handle.
*/
#define XCSI_MAX_SPKT (512)
/* Number of media pads */
#define XILINX_CSI_MEDIA_PADS (2)
#define XCSI_DEFAULT_WIDTH (1920)
#define XCSI_DEFAULT_HEIGHT (1080)
#define XCSI_DPHY_CLK_MIN 197000000000UL
#define XCSI_DPHY_CLK_MAX 203000000000UL
#define XCSI_DPHY_CLK_REQ 200000000000UL
/*
* Macro to return "true" or "false" string if bit is set
*/
#define XCSI_GET_BITSET_STR(val, mask) (val) & (mask) ? "true" : "false"
#define XCSI_CLK_PROP BIT(0)
#define XCSI_DPHY_PROP BIT(1)
#define XCSI_DPHY_ADDR_PROP BIT(2)
/**
* struct xcsi2rxss_feature - dt or IP property structure
* @flags: Bitmask of properties enabled in IP or dt
*/
struct xcsi2rxss_feature {
u32 flags;
};
enum CSI_DataTypes {
MIPI_CSI_DT_FRAME_START_CODE = 0x00,
MIPI_CSI_DT_FRAME_END_CODE,
MIPI_CSI_DT_LINE_START_CODE,
MIPI_CSI_DT_LINE_END_CODE,
MIPI_CSI_DT_SYNC_RSVD_04,
MIPI_CSI_DT_SYNC_RSVD_05,
MIPI_CSI_DT_SYNC_RSVD_06,
MIPI_CSI_DT_SYNC_RSVD_07,
MIPI_CSI_DT_GSPKT_08,
MIPI_CSI_DT_GSPKT_09,
MIPI_CSI_DT_GSPKT_0A,
MIPI_CSI_DT_GSPKT_0B,
MIPI_CSI_DT_GSPKT_0C,
MIPI_CSI_DT_GSPKT_0D,
MIPI_CSI_DT_GSPKT_0E,
MIPI_CSI_DT_GSPKT_0F,
MIPI_CSI_DT_GLPKT_10,
MIPI_CSI_DT_GLPKT_11,
MIPI_CSI_DT_GLPKT_12,
MIPI_CSI_DT_GLPKT_13,
MIPI_CSI_DT_GLPKT_14,
MIPI_CSI_DT_GLPKT_15,
MIPI_CSI_DT_GLPKT_16,
MIPI_CSI_DT_GLPKT_17,
MIPI_CSI_DT_YUV_420_8B,
MIPI_CSI_DT_YUV_420_10B,
MIPI_CSI_DT_YUV_420_8B_LEGACY,
MIPI_CSI_DT_YUV_RSVD,
MIPI_CSI_DT_YUV_420_8B_CSPS,
MIPI_CSI_DT_YUV_420_10B_CSPS,
MIPI_CSI_DT_YUV_422_8B,
MIPI_CSI_DT_YUV_422_10B,
MIPI_CSI_DT_RGB_444,
MIPI_CSI_DT_RGB_555,
MIPI_CSI_DT_RGB_565,
MIPI_CSI_DT_RGB_666,
MIPI_CSI_DT_RGB_888,
MIPI_CSI_DT_RGB_RSVD_25,
MIPI_CSI_DT_RGB_RSVD_26,
MIPI_CSI_DT_RGB_RSVD_27,
MIPI_CSI_DT_RAW_6,
MIPI_CSI_DT_RAW_7,
MIPI_CSI_DT_RAW_8,
MIPI_CSI_DT_RAW_10,
MIPI_CSI_DT_RAW_12,
MIPI_CSI_DT_RAW_14,
MIPI_CSI_DT_RAW_16,
MIPI_CSI_DT_RAW_20,
MIPI_CSI_DT_USER_30,
MIPI_CSI_DT_USER_31,
MIPI_CSI_DT_USER_32,
MIPI_CSI_DT_USER_33,
MIPI_CSI_DT_USER_34,
MIPI_CSI_DT_USER_35,
MIPI_CSI_DT_USER_36,
MIPI_CSI_DT_USER_37,
MIPI_CSI_DT_RSVD_38,
MIPI_CSI_DT_RSVD_39,
MIPI_CSI_DT_RSVD_3A,
MIPI_CSI_DT_RSVD_3B,
MIPI_CSI_DT_RSVD_3C,
MIPI_CSI_DT_RSVD_3D,
MIPI_CSI_DT_RSVD_3E,
MIPI_CSI_DT_RSVD_3F
};
/**
* struct pixel_format - Data Type to string name structure
* @PixelFormat: MIPI CSI2 Data type
* @PixelFormatStr: String name of Data Type
*/
struct pixel_format {
enum CSI_DataTypes PixelFormat;
char PixelFormatStr[MAX_XIL_CSIDT_STR_LENGTH];
};
/**
* struct xcsi2rxss_event - Event log structure
* @mask: Event mask
* @name: Name of the event
* @counter: Count number of events
*/
struct xcsi2rxss_event {
u32 mask;
const char * const name;
unsigned int counter;
};
/*
* struct xcsi2rxss_core - Core configuration CSI2 Rx Subsystem device structure
* @dev: Platform structure
* @iomem: Base address of subsystem
* @irq: requested irq number
* @dphy_present: Flag for DPHY register interface presence
* @dphy_offset: DPHY registers offset
* @enable_active_lanes: If number of active lanes can be modified
* @max_num_lanes: Maximum number of lanes present
* @vfb: Video Format Bridge enabled or not
* @ppc: pixels per clock
* @vc: Virtual Channel
* @axis_tdata_width: AXI Stream data width
* @datatype: Data type filter
* @pxlformat: String with CSI pixel format from IP
* @num_lanes: Number of lanes requested from application
* @events: Structure to maintain event logs
* @vcx_events: Structure to maintain VCX event logs
* @en_vcx: If more than 4 VC are enabled.
* @cfg: Pointer to csi2rxss config structure
* @lite_aclk: AXI4-Lite interface clock
* @video_aclk: Video clock
* @dphy_clk_200M: 200MHz DPHY clock
* @rst_gpio: video_aresetn
*/
struct xcsi2rxss_core {
struct device *dev;
void __iomem *iomem;
int irq;
u32 dphy_offset;
bool dphy_present;
bool enable_active_lanes;
u32 max_num_lanes;
bool vfb;
u32 ppc;
u32 vc;
u32 axis_tdata_width;
u32 datatype;
const char *pxlformat;
u32 num_lanes;
struct xcsi2rxss_event *events;
struct xcsi2rxss_event *vcx_events;
bool en_vcx;
const struct xcsi2rxss_feature *cfg;
struct clk *lite_aclk;
struct clk *video_aclk;
struct clk *dphy_clk_200M;
struct gpio_desc *rst_gpio;
};
/**
* struct xcsi2rxss_state - CSI2 Rx Subsystem device structure
* @core: Core structure for MIPI CSI2 Rx Subsystem
* @subdev: The v4l2 subdev structure
* @ctrl_handler: control handler
* @formats: Active V4L2 formats on each pad
* @default_format: default V4L2 media bus format
* @vip_format: format information corresponding to the active format
* @event: Holds the short packet event
* @lock: mutex for serializing operations
* @pads: media pads
* @npads: number of pads
* @streaming: Flag for storing streaming state
* @suspended: Flag for storing suspended state
*
* This structure contains the device driver related parameters
*/
struct xcsi2rxss_state {
struct xcsi2rxss_core core;
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_mbus_framefmt formats;
struct v4l2_mbus_framefmt default_format;
const struct xvip_video_format *vip_format;
struct v4l2_event event;
struct mutex lock;
struct media_pad pads[XILINX_CSI_MEDIA_PADS];
unsigned int npads;
bool streaming;
bool suspended;
};
static const struct xcsi2rxss_feature xlnx_csi2rxss_v5_0 = {
.flags = XCSI_CLK_PROP | XCSI_DPHY_PROP | XCSI_DPHY_ADDR_PROP,
};
static const struct xcsi2rxss_feature xlnx_csi2rxss_v4_1 = {
.flags = XCSI_CLK_PROP | XCSI_DPHY_PROP,
};
static const struct xcsi2rxss_feature xlnx_csi2rxss_v4_0 = {
.flags = XCSI_CLK_PROP,
};
static const struct xcsi2rxss_feature xlnx_csi2rxss_v2_0 = {
.flags = 0,
};
static const struct of_device_id xcsi2rxss_of_id_table[] = {
{ .compatible = "xlnx,mipi-csi2-rx-subsystem-2.0",
.data = &xlnx_csi2rxss_v2_0 },
{ .compatible = "xlnx,mipi-csi2-rx-subsystem-3.0",
.data = &xlnx_csi2rxss_v2_0 },
{ .compatible = "xlnx,mipi-csi2-rx-subsystem-4.0",
.data = &xlnx_csi2rxss_v4_0 },
{ .compatible = "xlnx,mipi-csi2-rx-subsystem-4.1",
.data = &xlnx_csi2rxss_v4_1 },
{ .compatible = "xlnx,mipi-csi2-rx-subsystem-5.0",
.data = &xlnx_csi2rxss_v5_0 },
{ }
};
MODULE_DEVICE_TABLE(of, xcsi2rxss_of_id_table);
static inline struct xcsi2rxss_state *
to_xcsi2rxssstate(struct v4l2_subdev *subdev)
{
return container_of(subdev, struct xcsi2rxss_state, subdev);
}
/*
* Regsiter related operations
*/
static inline u32 xcsi2rxss_read(struct xcsi2rxss_core *xcsi2rxss,
u32 addr)
{
return ioread32(xcsi2rxss->iomem + addr);
}
static inline void xcsi2rxss_write(struct xcsi2rxss_core *xcsi2rxss,
u32 addr,
u32 value)
{
iowrite32(value, xcsi2rxss->iomem + addr);
}
static inline void xcsi2rxss_clr(struct xcsi2rxss_core *xcsi2rxss,
u32 addr,
u32 clr)
{
xcsi2rxss_write(xcsi2rxss,
addr,
xcsi2rxss_read(xcsi2rxss, addr) & ~clr);
}
static inline void xcsi2rxss_set(struct xcsi2rxss_core *xcsi2rxss,
u32 addr,
u32 set)
{
xcsi2rxss_write(xcsi2rxss,
addr,
xcsi2rxss_read(xcsi2rxss, addr) | set);
}
static const struct pixel_format pixel_formats[] = {
{ MIPI_CSI_DT_YUV_420_8B, "YUV420_8bit" },
{ MIPI_CSI_DT_YUV_420_10B, "YUV420_10bit" },
{ MIPI_CSI_DT_YUV_420_8B_LEGACY, "Legacy_YUV420_8bit" },
{ MIPI_CSI_DT_YUV_420_8B_CSPS, "YUV420_8bit_CSPS" },
{ MIPI_CSI_DT_YUV_420_10B_CSPS, "YUV420_10bit_CSPS" },
{ MIPI_CSI_DT_YUV_422_8B, "YUV422_8bit" },
{ MIPI_CSI_DT_YUV_422_10B, "YUV422_10bit" },
{ MIPI_CSI_DT_RGB_444, "RGB444" },
{ MIPI_CSI_DT_RGB_555, "RGB555" },
{ MIPI_CSI_DT_RGB_565, "RGB565" },
{ MIPI_CSI_DT_RGB_666, "RGB666" },
{ MIPI_CSI_DT_RGB_888, "RGB888" },
{ MIPI_CSI_DT_RAW_6, "RAW6" },
{ MIPI_CSI_DT_RAW_7, "RAW7" },
{ MIPI_CSI_DT_RAW_8, "RAW8" },
{ MIPI_CSI_DT_RAW_10, "RAW10" },
{ MIPI_CSI_DT_RAW_12, "RAW12" },
{ MIPI_CSI_DT_RAW_14, "RAW14"},
{ MIPI_CSI_DT_RAW_16, "RAW16"},
{ MIPI_CSI_DT_RAW_20, "RAW20"}
};
static struct xcsi2rxss_event xcsi2rxss_events[] = {
{ XCSI_ISR_FR_MASK, "Frame Received", 0 },
{ XCSI_ISR_VCX_MASK, "VCX Frame Errors", 0 },
{ XCSI_ISR_YUV420_MASK, "YUV 420 Word Count Error", 0 },
{ XCSI_ISR_ILC_MASK, "Invalid Lane Count Error", 0 },
{ XCSI_ISR_SPFIFOF_MASK, "Short Packet FIFO OverFlow Error", 0 },
{ XCSI_ISR_SPFIFONE_MASK, "Short Packet FIFO Not Empty", 0 },
{ XCSI_ISR_SLBF_MASK, "Streamline Buffer Full Error", 0 },
{ XCSI_ISR_STOP_MASK, "Lane Stop State", 0 },
{ XCSI_ISR_SOTERR_MASK, "SOT Error", 0 },
{ XCSI_ISR_SOTSYNCERR_MASK, "SOT Sync Error", 0 },
{ XCSI_ISR_ECC2BERR_MASK, "2 Bit ECC Unrecoverable Error", 0 },
{ XCSI_ISR_ECC1BERR_MASK, "1 Bit ECC Recoverable Error", 0 },
{ XCSI_ISR_CRCERR_MASK, "CRC Error", 0 },
{ XCSI_ISR_DATAIDERR_MASK, "Data Id Error", 0 },
{ XCSI_ISR_VC3FSYNCERR_MASK, "Virtual Channel 3 Frame Sync Error", 0 },
{ XCSI_ISR_VC3FLVLERR_MASK, "Virtual Channel 3 Frame Level Error", 0 },
{ XCSI_ISR_VC2FSYNCERR_MASK, "Virtual Channel 2 Frame Sync Error", 0 },
{ XCSI_ISR_VC2FLVLERR_MASK, "Virtual Channel 2 Frame Level Error", 0 },
{ XCSI_ISR_VC1FSYNCERR_MASK, "Virtual Channel 1 Frame Sync Error", 0 },
{ XCSI_ISR_VC1FLVLERR_MASK, "Virtual Channel 1 Frame Level Error", 0 },
{ XCSI_ISR_VC0FSYNCERR_MASK, "Virtual Channel 0 Frame Sync Error", 0 },
{ XCSI_ISR_VC0FLVLERR_MASK, "Virtual Channel 0 Frame Level Error", 0 }
};
#define XMIPICSISS_NUM_EVENTS ARRAY_SIZE(xcsi2rxss_events)
#define XMIPICSISS_VCX_START (4)
#define XMIPICSISS_MAX_VC (4)
#define XMIPICSISS_MAX_VCX (16)
/* There are 2 events frame sync and frame level error per VC */
#define XMIPICSISS_VCX_NUM_EVENTS ((XMIPICSISS_MAX_VCX -\
XMIPICSISS_MAX_VC) * 2)
/**
* xcsi2rxss_clr_and_set - Clear and set the register with a bitmask
* @xcsi2rxss: Xilinx MIPI CSI2 Rx Subsystem subdev core struct
* @addr: address of register
* @clr: bitmask to be cleared
* @set: bitmask to be set
*
* Clear a bit(s) of mask @clr in the register at address @addr, then set
* a bit(s) of mask @set in the register after.
*/
static void xcsi2rxss_clr_and_set(struct xcsi2rxss_core *xcsi2rxss,
u32 addr, u32 clr, u32 set)
{
u32 reg;
reg = xcsi2rxss_read(xcsi2rxss, addr);
reg &= ~clr;
reg |= set;
xcsi2rxss_write(xcsi2rxss, addr, reg);
}
/**
* xcsi2rxss_pxlfmtstrtodt - Convert pixel format string got from dts
* to data type.
* @pxlfmtstr: String obtained while parsing device node
*
* This function takes a CSI pixel format string obtained while parsing
* device tree node and converts it to data type.
*
* Eg. "RAW8" string is converted to 0x2A.
* Refer to MIPI CSI2 specification for details.
*
* Return: Equivalent pixel format value from table
*/
static u32 xcsi2rxss_pxlfmtstrtodt(const char *pxlfmtstr)
{
u32 Index;
u32 MaxEntries = ARRAY_SIZE(pixel_formats);
for (Index = 0; Index < MaxEntries; Index++) {
if (!strncmp(pixel_formats[Index].PixelFormatStr,
pxlfmtstr, MAX_XIL_CSIDT_STR_LENGTH))
return pixel_formats[Index].PixelFormat;
}
return -EINVAL;
}
/**
* xcsi2rxss_pxlfmtdttostr - Convert pixel format data type to string.
* @datatype: MIPI CSI-2 Data Type
*
* This function takes a CSI pixel format data type and returns a
* pointer to the string name.
*
* Eg. 0x2A returns "RAW8" string.
* Refer to MIPI CSI2 specification for details.
*
* Return: Equivalent pixel format string from table
*/
static const char *xcsi2rxss_pxlfmtdttostr(u32 datatype)
{
u32 Index;
u32 MaxEntries = ARRAY_SIZE(pixel_formats);
for (Index = 0; Index < MaxEntries; Index++) {
if (pixel_formats[Index].PixelFormat == datatype)
return pixel_formats[Index].PixelFormatStr;
}
return NULL;
}
/**
* xcsi2rxss_enable - Enable or disable the CSI Core
* @core: Core Xilinx CSI2 Rx Subsystem structure pointer
* @flag: true for enabling, false for disabling
*
* This function enables/disables the MIPI CSI2 Rx Subsystem core.
* After enabling the CSI2 Rx core, the DPHY is enabled in case the
* register interface for it is present.
*/
static void xcsi2rxss_enable(struct xcsi2rxss_core *core, bool flag)
{
u32 DphyCtrlRegOffset = core->dphy_offset + XDPHY_CTRLREG_OFFSET;
if (flag) {
xcsi2rxss_write(core, XCSI_CCR_OFFSET, XCSI_CCR_COREENB_MASK);
if (core->dphy_present)
xcsi2rxss_write(core, DphyCtrlRegOffset,
XDPHY_CTRLREG_DPHYEN_MASK);
} else {
xcsi2rxss_write(core, XCSI_CCR_OFFSET, 0);
if (core->dphy_present)
xcsi2rxss_write(core, DphyCtrlRegOffset, 0);
}
}
/**
* xcsi2rxss_interrupts_enable - Enable or disable CSI interrupts
* @core: Core Xilinx CSI2 Rx Subsystem structure pointer
* @flag: true for enabling, false for disabling
*
* This function enables/disables the interrupts for the MIPI CSI2
* Rx Subsystem.
*/
static void xcsi2rxss_interrupts_enable(struct xcsi2rxss_core *core, bool flag)
{
if (flag) {
xcsi2rxss_clr(core, XCSI_GIER_OFFSET, XCSI_GIER_GIE_MASK);
xcsi2rxss_write(core, XCSI_IER_OFFSET, XCSI_INTR_MASK);
xcsi2rxss_set(core, XCSI_GIER_OFFSET, XCSI_GIER_GIE_MASK);
} else {
xcsi2rxss_clr(core, XCSI_IER_OFFSET, XCSI_INTR_MASK);
xcsi2rxss_clr(core, XCSI_GIER_OFFSET, XCSI_GIER_GIE_MASK);
}
}
/**
* xcsi2rxss_reset - Does a soft reset of the MIPI CSI2 Rx Subsystem
* @core: Core Xilinx CSI2 Rx Subsystem structure pointer
*
* Return: 0 - on success OR -ETIME if reset times out
*/
static int xcsi2rxss_reset(struct xcsi2rxss_core *core)
{
u32 Timeout = XCSI_TIMEOUT_VAL;
xcsi2rxss_set(core, XCSI_CCR_OFFSET, XCSI_CCR_SOFTRESET_MASK);
while (xcsi2rxss_read(core, XCSI_CSR_OFFSET) & XCSI_CSR_RIPCD_MASK) {
if (Timeout == 0) {
dev_err(core->dev, "Xilinx CSI2 Rx Subsystem Soft Reset Timeout!\n");
return -ETIME;
}
Timeout--;
udelay(1);
}
xcsi2rxss_clr(core, XCSI_CCR_OFFSET, XCSI_CCR_SOFTRESET_MASK);
return 0;
}
static void xcsi2rxss_stop_stream(struct xcsi2rxss_state *xcsi2rxss)
{
xcsi2rxss_interrupts_enable(&xcsi2rxss->core, false);
xcsi2rxss_enable(&xcsi2rxss->core, false);
}
/**
* xcsi2rxss_irq_handler - Interrupt handler for CSI-2
* @irq: IRQ number
* @dev_id: Pointer to device state
*
* In the interrupt handler, a list of event counters are updated for
* corresponding interrupts. This is useful to get status / debug.
* If the short packet FIFO not empty or overflow interrupt is received
* capture the short packet and notify of event occurrence
*
* Return: IRQ_HANDLED after handling interrupts
*/
static irqreturn_t xcsi2rxss_irq_handler(int irq, void *dev_id)
{
struct xcsi2rxss_state *state = (struct xcsi2rxss_state *)dev_id;
struct xcsi2rxss_core *core = &state->core;
u32 status;
status = xcsi2rxss_read(core, XCSI_ISR_OFFSET) & XCSI_INTR_MASK;
dev_dbg(core->dev, "interrupt status = 0x%08x\n", status);
if (!status)
return IRQ_NONE;
if (status & XCSI_ISR_SPFIFONE_MASK) {
memset(&state->event, 0, sizeof(state->event));
state->event.type = V4L2_EVENT_XLNXCSIRX_SPKT;
*((u32 *)(&state->event.u.data)) =
xcsi2rxss_read(core, XCSI_SPKTR_OFFSET);
v4l2_subdev_notify_event(&state->subdev, &state->event);
}
if (status & XCSI_ISR_SPFIFOF_MASK) {
dev_alert(core->dev, "Short packet FIFO overflowed\n");
memset(&state->event, 0, sizeof(state->event));
state->event.type = V4L2_EVENT_XLNXCSIRX_SPKT_OVF;
v4l2_subdev_notify_event(&state->subdev, &state->event);
}
if (status & (XCSI_ISR_SLBF_MASK | XCSI_ISR_YUV420_MASK)) {
if (status & XCSI_ISR_SLBF_MASK)
dev_alert(core->dev, "Stream Line Buffer Full!\n");
if (status & XCSI_ISR_YUV420_MASK)
dev_alert(core->dev, "YUV 420 Word count error!\n");
if (core->rst_gpio) {
gpiod_set_value(core->rst_gpio, 1);
/* minimum 40 dphy_clk_200M cycles */
ndelay(250);
gpiod_set_value(core->rst_gpio, 0);
}
xcsi2rxss_stop_stream(state);
memset(&state->event, 0, sizeof(state->event));
state->event.type = V4L2_EVENT_XLNXCSIRX_SLBF;
v4l2_subdev_notify_event(&state->subdev, &state->event);
}
if (status & XCSI_ISR_ALLINTR_MASK) {
unsigned int i;
for (i = 0; i < XMIPICSISS_NUM_EVENTS; i++) {
if (!(status & core->events[i].mask))
continue;
core->events[i].counter++;
dev_dbg(core->dev, "%s: %d\n", core->events[i].name,
core->events[i].counter);
}
if (status & XCSI_ISR_VCX_MASK && core->en_vcx) {
u32 vcxstatus;
vcxstatus = xcsi2rxss_read(core, XCSI_VCXR_OFFSET);
vcxstatus &= XCSI_VCXR_MASK;
for (i = 0; i < XMIPICSISS_VCX_NUM_EVENTS; i++) {
if (!(vcxstatus & core->vcx_events[i].mask))
continue;
core->vcx_events[i].counter++;
}
xcsi2rxss_write(core, XCSI_VCXR_OFFSET, vcxstatus);
}
}
xcsi2rxss_write(core, XCSI_ISR_OFFSET, status);
return IRQ_HANDLED;
}
static void xcsi2rxss_reset_event_counters(struct xcsi2rxss_state *state)
{
int i;
for (i = 0; i < XMIPICSISS_NUM_EVENTS; i++)
state->core.events[i].counter = 0;
if (!state->core.en_vcx)
return;
for (i = 0; i < XMIPICSISS_VCX_NUM_EVENTS; i++)
state->core.vcx_events[i].counter = 0;
}
/**
* xcsi2rxss_log_counters - Print out the event counters.
* @state: Pointer to device state
*
*/
static void xcsi2rxss_log_counters(struct xcsi2rxss_state *state)
{
int i;
for (i = 0; i < XMIPICSISS_NUM_EVENTS; i++) {
if (state->core.events[i].counter > 0)
v4l2_info(&state->subdev, "%s events: %d\n",
state->core.events[i].name,
state->core.events[i].counter);
}
if (!state->core.en_vcx)
return;
for (i = 0; i < XMIPICSISS_VCX_NUM_EVENTS; i++) {
if (state->core.vcx_events[i].counter > 0)
v4l2_info(&state->subdev,
"VC %d Frame %s error vcx events: %d\n",
(i / 2) + XMIPICSISS_VCX_START,
i & 1 ? "Sync" : "Level",
state->core.vcx_events[i].counter);
}
}
/**
* xcsi2rxss_log_status - Logs the status of the CSI-2 Receiver
* @sd: Pointer to V4L2 subdevice structure
*
* This function prints the current status of Xilinx MIPI CSI-2
*
* Return: 0 on success
*/
static int xcsi2rxss_log_status(struct v4l2_subdev *sd)
{
struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
struct xcsi2rxss_core *core = &xcsi2rxss->core;
u32 reg, data, i, max_vc;
mutex_lock(&xcsi2rxss->lock);
xcsi2rxss_log_counters(xcsi2rxss);
v4l2_info(sd, "***** Core Status *****\n");
data = xcsi2rxss_read(core, XCSI_CSR_OFFSET);
v4l2_info(sd, "Short Packet FIFO Full = %s\n",
XCSI_GET_BITSET_STR(data, XCSI_CSR_SPFIFOFULL_MASK));
v4l2_info(sd, "Short Packet FIFO Not Empty = %s\n",
XCSI_GET_BITSET_STR(data, XCSI_CSR_SPFIFONE_MASK));
v4l2_info(sd, "Stream line buffer full = %s\n",
XCSI_GET_BITSET_STR(data, XCSI_CSR_SLBF_MASK));
v4l2_info(sd, "Soft reset/Core disable in progress = %s\n",
XCSI_GET_BITSET_STR(data, XCSI_CSR_RIPCD_MASK));
/* Clk & Lane Info */
v4l2_info(sd, "******** Clock Lane Info *********\n");
data = xcsi2rxss_read(core, XCSI_CLKINFR_OFFSET);
v4l2_info(sd, "Clock Lane in Stop State = %s\n",
XCSI_GET_BITSET_STR(data, XCSI_CLKINFR_STOP_MASK));
v4l2_info(sd, "******** Data Lane Info *********\n");
v4l2_info(sd, "Lane\tSoT Error\tSoT Sync Error\tStop State\n");
reg = XCSI_L0INFR_OFFSET;
for (i = 0; i < 4; i++) {
data = xcsi2rxss_read(core, reg);
v4l2_info(sd, "%d\t%s\t\t%s\t\t%s\n",
i,
XCSI_GET_BITSET_STR(data, XCSI_LXINFR_SOTERR_MASK),
XCSI_GET_BITSET_STR(data, XCSI_LXINFR_SOTSYNCERR_MASK),
XCSI_GET_BITSET_STR(data, XCSI_LXINFR_STOP_MASK));
reg += 4;
}
/* Virtual Channel Image Information */
v4l2_info(sd, "********** Virtual Channel Info ************\n");
v4l2_info(sd, "VC\tLine Count\tByte Count\tData Type\n");
if (core->en_vcx)
max_vc = XMIPICSISS_MAX_VCX;
else
max_vc = XMIPICSISS_MAX_VC;