aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/alpine-hal/eth/al_hal_pcie.h
blob: 1ddc8eb707496ea78a1b7f6df26419ff7d1a55d6 (plain) (blame)
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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
/*-
********************************************************************************
Copyright (C) 2015 Annapurna Labs Ltd.

This file may be licensed under the terms of the Annapurna Labs Commercial
License Agreement.

Alternatively, this file can be distributed under the terms of the GNU General
Public License V2 as published by the Free Software Foundation and can be
found at http://www.gnu.org/licenses/gpl-2.0.html

Alternatively, redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:

    *     Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

    *     Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*******************************************************************************/

/**
 * @defgroup grouppcie PCI Express Controller
 *  @{
 * @section overview Overview
 * This header file provide API for the HAL driver of the pcie port, the driver
 * provides the following functionalities:
 * - Port initialization
 * - Link operation
 * - Interrupts transactions generation (Endpoint mode).
 * - Configuration Access management functions
 * - Internal Translation Unit programming
 *
 * This API does not provide the following:
 * - PCIe transactions generation and reception (except interrupts as mentioned
 *   above) as this functionality is done by the port without need for sw
 *   intervention.
 * - Configuration Access: those transactions are generated automatically by
 *   the port (ECAM or ATU mode) when the CPU issues memory transaction
 *   through the fabric toward the PCIe port. This API provides management
 *   function for controlling the Configuration Access type and bus destination
 * - Interrupt Handling.
 * - Message Generation: common used messages are automatically generated, also,
 *   the ATU generic mechanism for generating various kind of messages.
 * - PCIe Port Management: both link and port power management features can be
 *   managed using the PCI/PCIe standard power management and PCIe capabilities
 *   registers.
 * - PCIe link and protocol error handling: the feature can be managed using
 *   the Advanced Error Handling PCIe capability registers.
 *
 * @section flows Software Flows
 * @subsection init Initialization
 *   - allocation and set zeros al_pcie_port and al_pcie_pf structures handles
 *   - call al_pcie_port_handle_init() with pointer to the allocated
 *     al_pcie_port handle, address of the port internal registers space, and
 *     port id.
 *   - call al_pcie_pf_handle_init() with pointer to the al_pcie_port handle
 *     and pf_number.
 *   - set the port mode, End-Point or Root-Compex (default).
 *   - set number of lanes connected to the controller.
 *   - enable the controller using the al_pcie_port_enable(). note that this
 *     function expect the virtual address of the PBS Functional Registers.
 *   - wait for 2000 South-bridge cycles.
 *   - prepare al_pcie_port_config_params and al_pcie_pf_config_params
 *     structures depending on chip, board and system configuration.
 *     for example, when using the port as root complex, the operating_mode
 *     field should be set to AL_PCIE_OPERATING_MODE_RC. In this example we
 *     prepare the following configuration:
 *     For port configuration
 *     - Root Complex mode
 *     - Set the Max Link Speed to Gen2
 *     - Set the max lanes width to 2 (x2)
 *     - Disable reversal mode
 *     - Enable Snoops to support I/O Hardware cache coherency
 *     - Enable pcie core RAM parity
 *     - Enable pcie core AXI parity
 *     - Keep transaction layer default credits
 *     For pf configuration
 *     - No EP parameters
 *     - No SR-IOV parameters
 *     so the structures we prepare:
 *     @code
 *     - struct al_pcie_link_params link_params = {
 *		AL_PCIE_LINK_SPEED_GEN2,
 *		AL_FALSE,	// disable reversal mode
 *		AL_PCIE_MPS_DEFAULT};
 *
 *     - struct al_pcie_port_config_params config_params = {
 *		&link_params,
 *		AL_TRUE, // enable Snoop for inbound memory transactions
 *		AL_TRUE, // enable pcie port RAM parity
 *		AL_TRUE, // enable pcie port AXI parity
 *		NULL, // use default latency/replay timers
 *		NULL, // use default gen2 pipe params
 *		NULL, // gen3_params not needed when max speed set to Gen2
 *		NULL, // don't change TL credits
 *		NULL, // end point params not needed
 *		AL_FALSE, //no fast link
 *		AL_FALSE};	//return 0xFFFFFFFF for read transactions with
 *				//pci target error
 *	@endcode
 *	- now call al_pcie_port_config() with pcie_port and port_config_params
 * @subsection link-init Link Initialization
 *  - once the port configured, we can start PCIe link:
 *  - call al_pcie_link_start()
 *  - call al_pcie_link_up_wait()
 *  - allocate al_pcie_link_status struct and call al_pcie_link_status() and
 *    check the link is established.
 *
 *  @subsection  cap Configuration Access Preparation
 *  - Once the link is established, we can prepare the port for pci
 *  configuration access, this stage requires system knowledge about the PCI
 *  buses enumeration. For example, if 5 buses were discovered on previously
 *  scanned root complex port, then we should start enumeration from bus 5 (PCI
 *  secondary bus), the sub-ordinary bus will be temporarily set to maximum
 *  value (255) until the scan process under this bus is finished, then it will
 *  updated to the maximum bus value found. So we use the following sequence:
 *  - call al_pcie_secondary_bus_set() with sec-bus = 5
 *  - call al_pcie_subordinary_bus_set() with sub-bus = 255
 *
 *  @subsection cfg Configuration (Cfg) Access Generation
 *  - we assume using ECAM method, in this method, the software issues pcie Cfg
 *  access by accessing the ECAM memory space of the pcie port. For example, to
 *  issue 4 byte Cfg Read from bus B, Device D, Function F and register R, the
 *  software issues 4 byte read access to the following physical address
 *  ECAM base address of the port + (B << 20) + (D << 15) + (F << 12) + R.
 *  But, as the default size of the ECAM address space is less than
 *  needed full range (256MB), we modify the target_bus value prior to Cfg
 *  access in order make the port generate Cfg access with bus value set to the
 *  value of the target_bus rather than bits 27:20 of the physical address.
 *  - call al_pcie_target_bus_set() with target_bus set to the required bus of
 *   the next Cfg access to be issued, mask_target_bus will be set to 0xff.
 *   no need to call that function if the next Cfg access bus equals to the last
 *   value set to target_bus.
 *
 *      @file  al_hal_pcie.h
 *      @brief HAL Driver Header for the Annapurna Labs PCI Express port.
 */

#ifndef _AL_HAL_PCIE_H_
#define _AL_HAL_PCIE_H_

#include "al_hal_common.h"
#include "al_hal_pcie_regs.h"

/******************************************************************************/
/********************************* Constants **********************************/
/******************************************************************************/

/** Inbound header credits sum - rev 0/1/2 */
#define AL_PCIE_REV_1_2_IB_HCRD_SUM			97
/** Inbound header credits sum - rev 3 */
#define AL_PCIE_REV3_IB_HCRD_SUM			259

/** Number of extended registers */
#define AL_PCIE_EX_REGS_NUM				40

/*******************************************************************************
 * PCIe AER uncorrectable error bits
 * To be used with the following functions:
 * - al_pcie_aer_config
 * - al_pcie_aer_uncorr_get_and_clear
 ******************************************************************************/
/** Data Link Protocol Error */
#define AL_PCIE_AER_UNCORR_DLP_ERR			AL_BIT(4)
/** Poisoned TLP */
#define AL_PCIE_AER_UNCORR_POISIONED_TLP		AL_BIT(12)
/** Flow Control Protocol Error */
#define AL_PCIE_AER_UNCORR_FLOW_CTRL_ERR		AL_BIT(13)
/** Completion Timeout */
#define AL_PCIE_AER_UNCORR_COMPL_TO			AL_BIT(14)
/** Completer Abort */
#define AL_PCIE_AER_UNCORR_COMPL_ABT			AL_BIT(15)
/** Unexpected Completion */
#define AL_PCIE_AER_UNCORR_UNEXPCTED_COMPL		AL_BIT(16)
/** Receiver Overflow */
#define AL_PCIE_AER_UNCORR_RCV_OVRFLW			AL_BIT(17)
/** Malformed TLP */
#define AL_PCIE_AER_UNCORR_MLFRM_TLP			AL_BIT(18)
/** ECRC Error */
#define AL_PCIE_AER_UNCORR_ECRC_ERR			AL_BIT(19)
/** Unsupported Request Error */
#define AL_PCIE_AER_UNCORR_UNSUPRT_REQ_ERR		AL_BIT(20)
/** Uncorrectable Internal Error */
#define AL_PCIE_AER_UNCORR_INT_ERR			AL_BIT(22)
/** AtomicOp Egress Blocked */
#define AL_PCIE_AER_UNCORR_ATOMIC_EGRESS_BLK		AL_BIT(24)

/*******************************************************************************
 * PCIe AER correctable error bits
 * To be used with the following functions:
 * - al_pcie_aer_config
 * - al_pcie_aer_corr_get_and_clear
 ******************************************************************************/
/** Receiver Error */
#define AL_PCIE_AER_CORR_RCV_ERR			AL_BIT(0)
/** Bad TLP */
#define AL_PCIE_AER_CORR_BAD_TLP			AL_BIT(6)
/** Bad DLLP */
#define AL_PCIE_AER_CORR_BAD_DLLP			AL_BIT(7)
/** REPLAY_NUM Rollover */
#define AL_PCIE_AER_CORR_RPLY_NUM_ROLL_OVR		AL_BIT(8)
/** Replay Timer Timeout */
#define AL_PCIE_AER_CORR_RPLY_TMR_TO			AL_BIT(12)
/** Advisory Non-Fatal Error */
#define AL_PCIE_AER_CORR_ADVISORY_NON_FTL_ERR		AL_BIT(13)
/** Corrected Internal Error */
#define AL_PCIE_AER_CORR_INT_ERR			AL_BIT(14)

/** The AER erroneous TLP header length [num DWORDs] */
#define AL_PCIE_AER_ERR_TLP_HDR_NUM_DWORDS		4

/******************************************************************************/
/************************* Data Structures and Types **************************/
/******************************************************************************/

/**
 * al_pcie_ib_hcrd_config: data structure internally used in order to config
 * inbound posted/non-posted parameters.
 * Note: it's required to have this structure in pcie_port handle since it has
 *	 a state (required/not-required) which is determined by outbound
 *	 outstanding configuration
 */
struct al_pcie_ib_hcrd_config {
	/* Internally used - see 'al_pcie_ib_hcrd_os_ob_reads_config' */
	unsigned int	nof_np_hdr;

	/* Internally used - see 'al_pcie_ib_hcrd_os_ob_reads_config' */
	unsigned int	nof_p_hdr;
};

/* The Max Payload Size. Measured in bytes.
 *   DEFAULT: do not change the current MPS
 */
enum al_pcie_max_payload_size {
	AL_PCIE_MPS_DEFAULT,
	AL_PCIE_MPS_128		= 0,
	AL_PCIE_MPS_256		= 1,
	AL_PCIE_MPS_512		= 2,
	AL_PCIE_MPS_1024	= 3,
	AL_PCIE_MPS_2048	= 4,
	AL_PCIE_MPS_4096	= 5,
};

/**
 * al_pcie_port: data structure used by the HAL to handle a specific pcie port.
 * this structure is allocated and set to zeros by the upper layer, then it is
 * initialized by the al_pcie_port_handle_init() that should be called before any
 * other function of this API. later, this handle passed to the API functions.
 */
struct al_pcie_port {
	void __iomem		*pcie_reg_base;
	struct al_pcie_regs 	regs_ptrs;
	struct al_pcie_regs	*regs;
	uint32_t		*ex_regs_ptrs[AL_PCIE_EX_REGS_NUM];
	void			*ex_regs;
	void __iomem		*pbs_regs;

	/* Revision ID */
	uint8_t		rev_id;
	unsigned int	port_id;
	uint8_t		max_lanes;
	uint8_t		max_num_of_pfs;

	/* Internally used */
	struct al_pcie_ib_hcrd_config ib_hcrd_config;
};

/**
 * al_pcie_pf: the pf handle, a data structure used to handle PF specific
 * functionality. Initialized using "al_pcie_pf_handle_init()"
 */
struct al_pcie_pf {
	unsigned int		pf_num;
	struct al_pcie_port	*pcie_port;
};

/** Operating mode (endpoint, root complex) */
enum al_pcie_operating_mode {
	AL_PCIE_OPERATING_MODE_EP,
	AL_PCIE_OPERATING_MODE_RC,
	AL_PCIE_OPERATING_MODE_UNKNOWN
};

/* The maximum link speed, measured GT/s (Giga transfer / second)
 *   DEFAULT: do not change the current speed
 *   GEN1: 2.5 GT/s
 *   GEN2: 5 GT/s
 *   GEN3: 8GT/s
 *
 *   Note: The values of this enumerator are important for proper behavior
 */
enum al_pcie_link_speed {
	AL_PCIE_LINK_SPEED_DEFAULT,
	AL_PCIE_LINK_SPEED_GEN1 = 1,
	AL_PCIE_LINK_SPEED_GEN2 = 2,
	AL_PCIE_LINK_SPEED_GEN3 = 3
};

/** PCIe capabilities that supported by a specific port */
struct al_pcie_max_capability {
	al_bool		end_point_mode_supported;
	al_bool		root_complex_mode_supported;
	enum al_pcie_link_speed	max_speed;
	uint8_t		max_lanes;
	al_bool		reversal_supported;
	uint8_t		atu_regions_num;
	uint32_t	atu_min_size;
};

/** PCIe link related parameters */
struct al_pcie_link_params {
	enum al_pcie_link_speed	max_speed;
	al_bool			enable_reversal;
	enum al_pcie_max_payload_size	max_payload_size;

};

/** PCIe gen2 link parameters */
struct al_pcie_gen2_params {
	al_bool	tx_swing_low; /* set tx swing low when true, and tx swing full when false */
	al_bool	tx_compliance_receive_enable;
	al_bool	set_deemphasis;
};

/** PCIe gen 3 standard per lane equalization parameters */
struct al_pcie_gen3_lane_eq_params {
	uint8_t		downstream_port_transmitter_preset;
	uint8_t		downstream_port_receiver_preset_hint;
	uint8_t		upstream_port_transmitter_preset;
	uint8_t		upstream_port_receiver_preset_hint;
};

/** PCIe gen 3 equalization parameters */
struct al_pcie_gen3_params {
	al_bool	perform_eq;
	al_bool	interrupt_enable_on_link_eq_request;
	struct al_pcie_gen3_lane_eq_params *eq_params; /* array of lanes params */
	int	eq_params_elements; /* number of elements in the eq_params array */

	al_bool	eq_disable; /* disables the equalization feature */
	al_bool eq_phase2_3_disable; /* Equalization Phase 2 and Phase 3 */
				     /* Disable (RC mode only) */
	uint8_t local_lf; /* Full Swing (FS) Value for Gen3 Transmit Equalization */
			  /* Value Range: 12 through 63 (decimal).*/

	uint8_t	local_fs; /* Low Frequency (LF) Value for Gen3 Transmit Equalization */
};

/** Transport Layer credits parameters */
struct al_pcie_tl_credits_params {
};

/** Various configuration features */
struct al_pcie_features {
	/**
	 * Enable MSI fix from the SATA to the PCIe EP
	 * Only valid for port 0, when enabled as EP
	 */
	al_bool sata_ep_msi_fix;
};

/**
 * Inbound posted/non-posted header credits and outstanding outbound reads
 * completion header configuration
 *
 * Constraints:
 * - nof_cpl_hdr + nof_np_hdr + nof_p_hdr ==
 *			AL_PCIE_REV_1_2_IB_HCRD_SUM/AL_PCIE_REV3_IB_HCRD_SUM
 * - nof_cpl_hdr > 0
 * - nof_p_hdr > 0
 * - nof_np_hdr > 0
 */
struct al_pcie_ib_hcrd_os_ob_reads_config {
	/** Max number of outstanding outbound reads */
	uint8_t nof_outstanding_ob_reads;

	/**
	 * This value set the possible outstanding headers CMPLs , the core
	 * can get (the core always advertise infinite credits for CMPLs).
	 */
	unsigned int nof_cpl_hdr;

	/**
	 * This value set the possible outstanding headers reads (non-posted
	 * transactions), the core can get  (it set the value in the init FC
	 * process).
	 */
	unsigned int nof_np_hdr;

	/**
	 * This value set the possible outstanding headers writes (posted
	 * transactions), the core can get  (it set the value in the init FC
	 * process).
	 */
	unsigned int nof_p_hdr;
};

/** PCIe Ack/Nak Latency and Replay timers */
struct al_pcie_latency_replay_timers {
	uint16_t	round_trip_lat_limit;
	uint16_t	replay_timer_limit;
};

/* SRIS KP counter values */
struct al_pcie_sris_params {
	/** set to AL_TRUE to use defaults and ignore the other parameters */
	al_bool		use_defaults;
	uint16_t	kp_counter_gen3;	/* only for Gen3 */
	uint16_t	kp_counter_gen21;
};

/** Relaxed ordering params */
struct al_pcie_relaxed_ordering_params {
	al_bool		enable_tx_relaxed_ordering;
	al_bool		enable_rx_relaxed_ordering;
};

/** PCIe port configuration parameters
 * This structure includes the parameters that the HAL should apply to the port
 * (by al_pcie_port_config()).
 * The fields that are pointers (e.g. link_params) can be set to NULL, in that
 * case, the al_pcie_port_config() will keep the current HW settings.
 */
struct al_pcie_port_config_params {
	struct al_pcie_link_params		*link_params;
	al_bool					enable_axi_snoop;
	al_bool					enable_ram_parity_int;
	al_bool					enable_axi_parity_int;
	struct al_pcie_latency_replay_timers	*lat_rply_timers;
	struct al_pcie_gen2_params		*gen2_params;
	struct al_pcie_gen3_params		*gen3_params;
	struct al_pcie_tl_credits_params	*tl_credits;
	struct al_pcie_features			*features;
	/* Sets all internal timers to Fast Mode for speeding up simulation.*/
	al_bool					fast_link_mode;
	/*
	 * when true, the PCI unit will return Slave Error/Decoding Error to the master unit in case
	 * of error. when false, the value 0xFFFFFFFF will be returned without error indication.
	 */
	al_bool					enable_axi_slave_err_resp;
	struct al_pcie_sris_params		*sris_params;
	struct al_pcie_relaxed_ordering_params	*relaxed_ordering_params;
};

/** BAR register configuration parameters (Endpoint Mode only) */
struct al_pcie_ep_bar_params {
	al_bool		enable;
	al_bool		memory_space; /**< memory or io */
	al_bool		memory_64_bit; /**< is memory space is 64 bit */
	al_bool		memory_is_prefetchable;
	uint64_t	size; /* the bar size in bytes */
};

/** PF config params (EP mode only) */
struct al_pcie_pf_config_params {
	al_bool				cap_d1_d3hot_dis;
	al_bool				cap_flr_dis;
	al_bool				cap_aspm_dis;
	al_bool				bar_params_valid;
	struct al_pcie_ep_bar_params	bar_params[6];
	struct al_pcie_ep_bar_params	exp_bar_params;/* expansion ROM BAR*/
};

/** PCIe link status */
struct al_pcie_link_status {
	al_bool			link_up;
	enum al_pcie_link_speed	speed;
	uint8_t			lanes;
	uint8_t			ltssm_state;
};

/** PCIe lane status */
struct al_pcie_lane_status {
	al_bool			is_reset;
	enum al_pcie_link_speed	requested_speed;
};

/** PCIe MSIX capability configuration parameters */
struct al_pcie_msix_params {
	uint16_t	table_size;
	uint16_t	table_offset;
	uint8_t		table_bar;
	uint16_t	pba_offset;
	uint16_t	pba_bar;
};

/** PCIE AER capability parameters */
struct al_pcie_aer_params {
	/** ECRC Generation Enable */
	al_bool		ecrc_gen_en;
	/** ECRC Check Enable */
	al_bool		ecrc_chk_en;

	/**
	 * Enabled reporting of correctable errors (bit mask)
	 * See 'AL_PCIE_AER_CORR_*' for details
	 * 0 - no reporting at all
	 */
	unsigned int	enabled_corr_err;
	/**
	 * Enabled reporting of non-fatal uncorrectable errors (bit mask)
	 * See 'AL_PCIE_AER_UNCORR_*' for details
	 * 0 - no reporting at all
	 */
	unsigned int	enabled_uncorr_non_fatal_err;
	/**
	 * Enabled reporting of fatal uncorrectable errors (bit mask)
	 * See 'AL_PCIE_AER_UNCORR_*' for details
	 * 0 - no reporting at all
	 */
	unsigned int	enabled_uncorr_fatal_err;
};

/******************************************************************************/
/********************************** PCIe API **********************************/
/******************************************************************************/

/*************************** PCIe Initialization API **************************/

/**
 * Initializes a PCIe port handle structure.
 *
 * @param   pcie_port		an allocated, non-initialized instance.
 * @param   pcie_reg_base	the virtual base address of the port internal
 *				registers
 * @param   pbs_reg_base	the virtual base address of the pbs functional
 *				registers
 * @param   port_id		the port id (used mainly for debug messages)
 *
 * @return 0 if no error found.
 */
int al_pcie_port_handle_init(struct al_pcie_port *pcie_port,
			 void __iomem *pcie_reg_base,
			 void __iomem *pbs_reg_base,
			 unsigned int port_id);

/**
 * Initializes a PCIe pf handle structure
 * @param  pcie_pf   an allocated, non-initialized instance of pf handle
 * @param  pcie_port pcie port handle
 * @param  pf_num    physical function number
 * @return           0 if no error found
 */
int al_pcie_pf_handle_init(
	struct al_pcie_pf *pcie_pf,
	struct al_pcie_port *pcie_port,
	unsigned int pf_num);

/************************** Pre PCIe Port Enable API **************************/

/**
 * @brief set current pcie operating mode (root complex or endpoint)
 * This function can be called only before enabling the controller using
 * al_pcie_port_enable().
 *
 * @param pcie_port pcie port handle
 * @param mode pcie operating mode
 *
 * @return 0 if no error found.
 */
int al_pcie_port_operating_mode_config(struct al_pcie_port *pcie_port,
				  enum al_pcie_operating_mode mode);

/**
 * Configure number of lanes connected to this port.
 * This function can be called only before enabling the controller using al_pcie_port_enable().
 *
 * @param pcie_port pcie port handle
 * @param lanes number of lanes
 * Note: this function must be called before any al_pcie_port_config() calls
 *
 * @return 0 if no error found.
 */
int al_pcie_port_max_lanes_set(struct al_pcie_port *pcie_port, uint8_t lanes);

/**
 * Set maximum physical function numbers
 * @param pcie_port      pcie port handle
 * @param max_num_of_pfs number of physical functions
 * Note: this function must be called before any al_pcie_pf_config() calls
 */
int al_pcie_port_max_num_of_pfs_set(
	struct al_pcie_port *pcie_port,
	uint8_t max_num_of_pfs);

/**
 * @brief Inbound posted/non-posted header credits and outstanding outbound
 *        reads completion header configuration
 *
 * @param	pcie_port pcie port handle
 * @param	ib_hcrd_os_ob_reads_config
 * 		Inbound header credits and outstanding outbound reads
 * 		configuration
 */
int al_pcie_port_ib_hcrd_os_ob_reads_config(
	struct al_pcie_port *pcie_port,
	struct al_pcie_ib_hcrd_os_ob_reads_config *ib_hcrd_os_ob_reads_config);

/** return PCIe operating mode
 * @param pcie_port	pcie port handle
 * @return		operating mode
 */
enum al_pcie_operating_mode al_pcie_operating_mode_get(
	struct al_pcie_port *pcie_port);

/**************************** PCIe Port Enable API ****************************/

/** Enable PCIe unit (deassert reset)
 *
 * @param   pcie_port pcie port handle
 *
 * @return 0 if no error found.
 */
int al_pcie_port_enable(struct al_pcie_port *pcie_port);

/** Disable PCIe unit (assert reset)
 *
 * @param   pcie_port pcie port handle
 */
void al_pcie_port_disable(struct al_pcie_port *pcie_port);

/**
 * Port memory shutdown/up
 * Caution: This function can be called only when the controller is disabled
 *
 * @param pcie_port pcie port handle
 * @param enable memory shutdown enable or disable
 *
 */
int al_pcie_port_memory_shutdown_set(
	struct al_pcie_port	*pcie_port,
	al_bool			enable);

/**
 * Check if port enabled or not
 * @param  pcie_port pcie port handle
 * @return           AL_TRUE of port enabled and AL_FALSE otherwise
 */
al_bool al_pcie_port_is_enabled(struct al_pcie_port *pcie_port);

/*************************** PCIe Configuration API ***************************/

/**
 * @brief   configure pcie port (mode, link params, etc..)
 * this function must be called before initializing the link
 *
 * @param pcie_port pcie port handle
 * @param params configuration structure.
 *
 * @return  0 if no error found
 */
int al_pcie_port_config(struct al_pcie_port *pcie_port,
			const struct al_pcie_port_config_params *params);

/**
 * @brief Configure a specific PF (EP params, sriov params, ...)
 * this function must be called before any datapath transactions
 *
 * @param pcie_pf	pcie pf handle
 * @param params	configuration structure.
 *
 * @return		0 if no error found
 */
int al_pcie_pf_config(
	struct al_pcie_pf *pcie_pf,
	const struct al_pcie_pf_config_params *params);

/************************** PCIe Link Operations API **************************/

/**
 * @brief   start pcie link
 *
 * @param   pcie_port pcie port handle
 *
 * @return  0 if no error found
 */
int al_pcie_link_start(struct al_pcie_port *pcie_port);

/**
 * @brief   stop pcie link
 *
 * @param   pcie_port pcie port handle
 *
 * @return  0 if no error found
 */
int al_pcie_link_stop(struct al_pcie_port *pcie_port);

/**
 * @brief   trigger link-disable
 *
 * @param   pcie_port pcie port handle
 * @param   disable   AL_TRUE to disable the link and AL_FALSE to enable it
 *
 * Note: this functionality differs from "al_pcie_link_stop" as it's a spec
 *       functionality where both sides of the PCIe agrees to disable the link
 * @return  0 if no error found
 */
int al_pcie_link_disable(struct al_pcie_port *pcie_port, al_bool disable);

/**
 * @brief   wait for link up indication
 * this function waits for link up indication, it polls LTSSM state until link is ready
 *
 * @param   pcie_port pcie port handle
 * @param   timeout_ms maximum timeout in milli-seconds to wait for link up
 *
 * @return  0 if link up indication detected
 * 	    -ETIME if not.
 */
int al_pcie_link_up_wait(struct al_pcie_port *pcie_port, uint32_t timeout_ms);

/**
 * @brief   get link status
 *
 * @param   pcie_port pcie port handle
 * @param   status structure for link status
 *
 * @return  0 if no error found
 */
int al_pcie_link_status(struct al_pcie_port *pcie_port, struct al_pcie_link_status *status);

/**
 * @brief   get lane status
 *
 * @param	pcie_port
 *		pcie port handle
 * @param	lane
 *		PCIe lane
 * @param	status
 *		Pointer to returned structure for lane status
 *
 */
void al_pcie_lane_status_get(
	struct al_pcie_port		*pcie_port,
	unsigned int			lane,
	struct al_pcie_lane_status	*status);

/**
 * @brief   trigger hot reset
 *
 * @param   pcie_port pcie port handle
 * @param   enable   AL_TRUE to enable hot-reset and AL_FALSE to disable it
 *
 * @return  0 if no error found
 */
int al_pcie_link_hot_reset(struct al_pcie_port *pcie_port, al_bool enable);

/**
 * @brief   trigger link-retain
 * this function initiates Link retraining by directing the Physical Layer LTSSM
 * to the Recovery state. If the LTSSM is already in Recovery or Configuration,
 * re-entering Recovery is permitted but not required.

 * @param   pcie_port pcie port handle
 *
 * Note: there's no need to disable initiating link-retrain
 * @return  0 if no error found
 */
int al_pcie_link_retrain(struct al_pcie_port *pcie_port);

/**
 * @brief   change port speed
 * this function changes the port speed, it doesn't wait for link re-establishment
 *
 * @param   pcie_port pcie port handle
 * @param   new_speed the new speed gen to set
 *
 * @return  0 if no error found
 */
int al_pcie_link_change_speed(struct al_pcie_port *pcie_port, enum al_pcie_link_speed new_speed);

/* TODO: check if this function needed */
int al_pcie_link_change_width(struct al_pcie_port *pcie_port, uint8_t width);

/**************************** Post Link Start API *****************************/

/************************** Snoop Configuration API ***************************/

/**
 * @brief   configure pcie port axi snoop
 *
 * @param pcie_port pcie port handle
 * @param enable_axi_snoop enable snoop.
 *
 * @return  0 if no error found
 */
/* TODO: Can this API be called after port enable? */
int al_pcie_port_snoop_config(struct al_pcie_port *pcie_port,
				al_bool enable_axi_snoop);

/************************** Configuration Space API ***************************/

/**
 * Configuration Space Access Through PCI-E_ECAM_Ext PASW (RC mode only)
 */

/**
 * @brief   get base address of pci configuration space header
 * @param   pcie_pf	pcie pf handle
 * @param   addr	pointer for returned address;
 * @return              0 if no error found
 */
int al_pcie_config_space_get(
	struct al_pcie_pf *pcie_pf,
	uint8_t __iomem **addr);

/**
 * Read data from the local configuration space
 *
 * @param	pcie_pf	pcie	pf handle
 * @param	reg_offset	Configuration space register offset
 * @return	Read data
 */
uint32_t al_pcie_local_cfg_space_read(
	struct al_pcie_pf	*pcie_pf,
	unsigned int		reg_offset);

/**
 * Write data to the local configuration space
 *
 * @param	pcie_pf		PCIe pf handle
 * @param	reg_offset	Configuration space register offset
 * @param	data		Data to write
 * @param	cs2		Should be AL_TRUE if dbi_cs2 must be asserted
 *				to enable writing to this register, according to
 *				the PCIe Core specifications
 * @param	allow_ro_wr	AL_TRUE to allow writing into read-only regs
 *
 */
void al_pcie_local_cfg_space_write(
	struct al_pcie_pf	*pcie_pf,
	unsigned int		reg_offset,
	uint32_t		data,
	al_bool			cs2,
	al_bool			allow_ro_wr);

/**
 * @brief   set target_bus and mask_target_bus
 * @param   pcie_port pcie port handle
 * @param   target_bus
 * @param   mask_target_bus
 * @return  0 if no error found
 */
int al_pcie_target_bus_set(struct al_pcie_port *pcie_port,
			   uint8_t target_bus,
			   uint8_t mask_target_bus);

/**
 * @brief   get target_bus and mask_target_bus
 * @param   pcie_port pcie port handle
 * @param   target_bus
 * @param   mask_target_bus
 * @return  0 if no error found
 */
int al_pcie_target_bus_get(struct al_pcie_port *pcie_port,
			   uint8_t *target_bus,
			   uint8_t *mask_target_bus);

/**
 * Set secondary bus number
 *
 * @param pcie_port pcie port handle
 * @param secbus pci secondary bus number
 *
 * @return 0 if no error found.
 */
int al_pcie_secondary_bus_set(struct al_pcie_port *pcie_port, uint8_t secbus);

/**
 * Set subordinary bus number
 *
 * @param   pcie_port pcie port handle
 * @param   subbus the highest bus number of all of the buses that can be reached
 *		downstream of the PCIE instance.
 *
 * @return 0 if no error found.
 */
int al_pcie_subordinary_bus_set(struct al_pcie_port *pcie_port,uint8_t subbus);

/**
 * @brief Enable/disable deferring incoming configuration requests until
 * initialization is complete. When enabled, the core completes incoming
 * configuration requests with a Configuration Request Retry Status.
 * Other incoming Requests complete with Unsupported Request status.
 *
 * @param pcie_port pcie port handle
 * @param en enable/disable
 */
void al_pcie_app_req_retry_set(struct al_pcie_port *pcie_port, al_bool en);

/*************** Internal Address Translation Unit (ATU) API ******************/

enum al_pcie_atu_dir {
	AL_PCIE_ATU_DIR_OUTBOUND = 0,
	AL_PCIE_ATU_DIR_INBOUND = 1,
};

enum al_pcie_atu_tlp {
	AL_PCIE_TLP_TYPE_MEM = 0,
	AL_PCIE_TLP_TYPE_IO = 2,
	AL_PCIE_TLP_TYPE_CFG0 = 4,
	AL_PCIE_TLP_TYPE_CFG1 = 5,
	AL_PCIE_TLP_TYPE_MSG = 0x10,
	AL_PCIE_TLP_TYPE_RESERVED = 0x1f
};

enum al_pcie_atu_response {
	AL_PCIE_RESPONSE_NORMAL = 0,
	AL_PCIE_RESPONSE_UR = 1,
	AL_PCIE_RESPONSE_CA = 2
};

struct al_pcie_atu_region {
	al_bool			enable;
	/* outbound or inbound */
	enum al_pcie_atu_dir	direction;
	/* region index */
	uint8_t			index;
	uint64_t		base_addr;
	/** limit marks the region's end address. only bits [39:0] are valid
	 * given the Alpine PoC maximum physical address space
	 */
	uint64_t		limit;
	/** the address that matches will be translated to this address + offset
	 */
	uint64_t		target_addr;
	al_bool			invert_matching;
	/* pcie tlp type*/
	enum al_pcie_atu_tlp	tlp_type;
	/* pcie frame header attr field*/
	uint8_t			attr;
	/**
	 * outbound specific params
	 */
	/* pcie message code */
	uint8_t			msg_code;
	al_bool			cfg_shift_mode;
	/**
	 * inbound specific params
	 */
	uint8_t			bar_number;
	/* BAR match mode, used in EP for MEM and IO tlps*/
	uint8_t			match_mode;
	/**
	 * For outbound: enables taking the function number of the translated
	 * TLP from the PCIe core. For inbound: enables ATU function match mode
	 * Note: this boolean is ignored in RC mode
	 */
	al_bool			function_match_bypass_mode;
	/**
	 * The function number to match/bypass (see previous parameter)
	 * Note: this parameter is ignored when previous param is FALSE
	 */
	uint8_t			function_match_bypass_mode_number;
	/* response code */
	enum al_pcie_atu_response response;
	al_bool			enable_attr_match_mode;
	al_bool			enable_msg_match_mode;
	/**
	 * USE WITH CAUTION: setting this boolean to AL_TRUE allows setting the
	 * outbound ATU even after link is already started. DO NOT SET this
	 * boolean to AL_TRUE unless there have been NO traffic before calling
	 * al_pcie_atu_region_set function
	 */
	al_bool			enforce_ob_atu_region_set;
};

/**
 * @brief   program internal ATU region entry
 * @param   pcie_port	pcie port handle
 * @param   atu_region	data structure that contains the region index and the
 *          translation parameters
 * @return  0 if no error
 */
int al_pcie_atu_region_set(
	struct al_pcie_port *pcie_port,
	struct al_pcie_atu_region *atu_region);

/**
 * @brief  get internal ATU is enabled and base/target addresses
 * @param  pcie_port   pcie port handle
 * @param  direction   input: iATU direction (IB/OB)
 * @param  index       input: iATU index
 * @param  enable      output: AL_TRUE if the iATU is enabled
 * @param  base_addr   output: the iATU base address
 * @param  target_addr output: the iATU target address
 */
void al_pcie_atu_region_get_fields(
	struct al_pcie_port *pcie_port,
	enum al_pcie_atu_dir direction, uint8_t index,
	al_bool *enable, uint64_t *base_addr, uint64_t *target_addr);

/**
 * @brief   Configure axi io bar.
 *          every hit to this bar will override size to 4 bytes.
 * @param   pcie_port pcie port handle
 * @param   start the first address of the memory
 * @param   end the last address of the memory
 * @return
 */
void al_pcie_axi_io_config(
	struct al_pcie_port *pcie_port,
	al_phys_addr_t start,
	al_phys_addr_t end);

/************** Interrupt generation (Endpoint mode Only) API *****************/

enum al_pcie_legacy_int_type{
	AL_PCIE_LEGACY_INTA = 0,
	AL_PCIE_LEGACY_INTB,
	AL_PCIE_LEGACY_INTC,
	AL_PCIE_LEGACY_INTD
};

/**
 * @brief		generate INTx Assert/DeAssert Message
 * @param  pcie_pf	pcie pf handle
 * @param  assert	when true, Assert Message is sent
 * @param  type		type of message (INTA, INTB, etc)
 * @return		0 if no error found
 */
int al_pcie_legacy_int_gen(
	struct al_pcie_pf		*pcie_pf,
	al_bool				assert,
	enum al_pcie_legacy_int_type	type);

/**
 * @brief		generate MSI interrupt
 * @param  pcie_pf	pcie pf handle
 * @param  vector	the vector index to send interrupt for.
 * @return		0 if no error found
 */
int al_pcie_msi_int_gen(struct al_pcie_pf *pcie_pf, uint8_t vector);

/**
 * @brief   configure MSIX capability
 * @param   pcie_pf	pcie pf handle
 * @param   msix_params	MSIX capability configuration parameters
 * @return  0 if no error found
 */
int al_pcie_msix_config(
		struct al_pcie_pf		*pcie_pf,
		struct al_pcie_msix_params	*msix_params);

/**
 * @brief   check whether MSIX capability is enabled
 * @param   pcie_pf	pcie pf handle
 * @return  AL_TRUE if MSIX capability is enabled, AL_FALSE otherwise
 */
al_bool al_pcie_msix_enabled(struct al_pcie_pf	*pcie_pf);

/**
 * @brief   check whether MSIX capability is masked
 * @param   pcie_pf	pcie pf handle
 * @return  AL_TRUE if MSIX capability is masked, AL_FALSE otherwise
 */
al_bool al_pcie_msix_masked(struct al_pcie_pf *pcie_pf);

/******************** Advanced Error Reporting (AER) API **********************/

/**
 * @brief   configure AER capability
 * @param   pcie_pf	pcie pf handle
 * @param   params	AER capability configuration parameters
 * @return  0 if no error found
 */
int al_pcie_aer_config(
	struct al_pcie_pf		*pcie_pf,
	struct al_pcie_aer_params	*params);

/**
 * @brief   AER uncorretable errors get and clear
 * @param   pcie_pf	pcie pf handle
 * @return  bit mask of uncorrectable errors - see 'AL_PCIE_AER_UNCORR_*' for
 *          details
 */
unsigned int al_pcie_aer_uncorr_get_and_clear(struct al_pcie_pf	*pcie_pf);

/**
 * @brief   AER corretable errors get and clear
 * @param   pcie_pf	pcie pf handle
 * @return  bit mask of correctable errors - see 'AL_PCIE_AER_CORR_*' for
 *          details
 */
unsigned int al_pcie_aer_corr_get_and_clear(struct al_pcie_pf	*pcie_pf);

/**
 * @brief   AER get the header for the TLP corresponding to a detected error
 * @param   pcie_pf	pcie pf handle
 * @param   hdr		pointer to an array for getting the header
 */
void al_pcie_aer_err_tlp_hdr_get(
	struct al_pcie_pf	*pcie_pf,
	uint32_t		hdr[AL_PCIE_AER_ERR_TLP_HDR_NUM_DWORDS]);

/******************** Loop-Back mode (RC and Endpoint modes) ******************/

/**
 * @brief   enter local pipe loop-back mode
 *  This mode will connect the pipe RX signals to TX.
 *  no need to start link when using this mode.
 *  Gen3 equalization must be disabled before enabling this mode
 *  The caller must make sure the port is ready to accept the TLPs it sends to
 *  itself. for example, BARs should be initialized before sending memory TLPs.
 *
 * @param   pcie_port pcie port handle
 * @return  0 if no error found
 */
int al_pcie_local_pipe_loopback_enter(struct al_pcie_port *pcie_port);

/**
 * @brief   exit local pipe loopback mode
 *
 * @param   pcie_port pcie port handle
 * @return  0 if no error found
 */
int al_pcie_local_pipe_loopback_exit(struct al_pcie_port *pcie_port);

/**
 * @brief   enter master remote loopback mode
 *  No need to configure the link partner to enter slave remote loopback mode
 *  as this should be done as response to special training sequence directives
 *  when master works in remote loopback mode.
 *  The caller must make sure the port is ready to accept the TLPs it sends to
 *  itself. for example, BARs should be initialized before sending memory TLPs.
 *
 * @param   pcie_port pcie port handle
 * @return  0 if no error found
 */
int al_pcie_remote_loopback_enter(struct al_pcie_port *pcie_port);

/**
 * @brief   exit remote loopback mode
 *
 * @param   pcie_port pcie port handle
 * @return  0 if no error found
 */
int al_pcie_remote_loopback_exit(struct al_pcie_port *pcie_port);

#endif
/** @} end of grouppcie group */