5555#define IMX95_PE0_GEN_CTRL_3 0x1058
5656#define IMX95_PCIE_LTSSM_EN BIT(0)
5757
58+ #define IMX95_PE0_LUT_ACSCTRL 0x1008
59+ #define IMX95_PEO_LUT_RWA BIT(16)
60+ #define IMX95_PE0_LUT_ENLOC GENMASK(4, 0)
61+
62+ #define IMX95_PE0_LUT_DATA1 0x100c
63+ #define IMX95_PE0_LUT_VLD BIT(31)
64+ #define IMX95_PE0_LUT_DAC_ID GENMASK(10, 8)
65+ #define IMX95_PE0_LUT_STREAM_ID GENMASK(5, 0)
66+
67+ #define IMX95_PE0_LUT_DATA2 0x1010
68+ #define IMX95_PE0_LUT_REQID GENMASK(31, 16)
69+ #define IMX95_PE0_LUT_MASK GENMASK(15, 0)
70+
71+ #define IMX95_SID_MASK GENMASK(5, 0)
72+ #define IMX95_MAX_LUT 32
73+
5874#define to_imx_pcie (x ) dev_get_drvdata((x)->dev)
5975
6076enum imx_pcie_variants {
@@ -87,6 +103,7 @@ enum imx_pcie_variants {
87103 * workaround suspend resume on some devices which are affected by this errata.
88104 */
89105#define IMX_PCIE_FLAG_BROKEN_SUSPEND BIT(9)
106+ #define IMX_PCIE_FLAG_HAS_LUT BIT(10)
90107
91108#define imx_check_flag (pci , val ) (pci->drvdata->flags & val)
92109
@@ -139,6 +156,9 @@ struct imx_pcie {
139156 struct device * pd_pcie_phy ;
140157 struct phy * phy ;
141158 const struct imx_pcie_drvdata * drvdata ;
159+
160+ /* Ensure that only one device's LUT is configured at any given time */
161+ struct mutex lock ;
142162};
143163
144164/* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */
@@ -930,6 +950,184 @@ static void imx_pcie_stop_link(struct dw_pcie *pci)
930950 imx_pcie_ltssm_disable (dev );
931951}
932952
953+ static int imx_pcie_add_lut (struct imx_pcie * imx_pcie , u16 rid , u8 sid )
954+ {
955+ struct dw_pcie * pci = imx_pcie -> pci ;
956+ struct device * dev = pci -> dev ;
957+ u32 data1 , data2 ;
958+ int free = -1 ;
959+ int i ;
960+
961+ if (sid >= 64 ) {
962+ dev_err (dev , "Invalid SID for index %d\n" , sid );
963+ return - EINVAL ;
964+ }
965+
966+ guard (mutex )(& imx_pcie -> lock );
967+
968+ /*
969+ * Iterate through all LUT entries to check for duplicate RID and
970+ * identify the first available entry. Configure this available entry
971+ * immediately after verification to avoid rescanning it.
972+ */
973+ for (i = 0 ; i < IMX95_MAX_LUT ; i ++ ) {
974+ regmap_write (imx_pcie -> iomuxc_gpr ,
975+ IMX95_PE0_LUT_ACSCTRL , IMX95_PEO_LUT_RWA | i );
976+ regmap_read (imx_pcie -> iomuxc_gpr , IMX95_PE0_LUT_DATA1 , & data1 );
977+
978+ if (!(data1 & IMX95_PE0_LUT_VLD )) {
979+ if (free < 0 )
980+ free = i ;
981+ continue ;
982+ }
983+
984+ regmap_read (imx_pcie -> iomuxc_gpr , IMX95_PE0_LUT_DATA2 , & data2 );
985+
986+ /* Do not add duplicate RID */
987+ if (rid == FIELD_GET (IMX95_PE0_LUT_REQID , data2 )) {
988+ dev_warn (dev , "Existing LUT entry available for RID (%d)" , rid );
989+ return 0 ;
990+ }
991+ }
992+
993+ if (free < 0 ) {
994+ dev_err (dev , "LUT entry is not available\n" );
995+ return - ENOSPC ;
996+ }
997+
998+ data1 = FIELD_PREP (IMX95_PE0_LUT_DAC_ID , 0 );
999+ data1 |= FIELD_PREP (IMX95_PE0_LUT_STREAM_ID , sid );
1000+ data1 |= IMX95_PE0_LUT_VLD ;
1001+ regmap_write (imx_pcie -> iomuxc_gpr , IMX95_PE0_LUT_DATA1 , data1 );
1002+
1003+ data2 = IMX95_PE0_LUT_MASK ; /* Match all bits of RID */
1004+ data2 |= FIELD_PREP (IMX95_PE0_LUT_REQID , rid );
1005+ regmap_write (imx_pcie -> iomuxc_gpr , IMX95_PE0_LUT_DATA2 , data2 );
1006+
1007+ regmap_write (imx_pcie -> iomuxc_gpr , IMX95_PE0_LUT_ACSCTRL , free );
1008+
1009+ return 0 ;
1010+ }
1011+
1012+ static void imx_pcie_remove_lut (struct imx_pcie * imx_pcie , u16 rid )
1013+ {
1014+ u32 data2 ;
1015+ int i ;
1016+
1017+ guard (mutex )(& imx_pcie -> lock );
1018+
1019+ for (i = 0 ; i < IMX95_MAX_LUT ; i ++ ) {
1020+ regmap_write (imx_pcie -> iomuxc_gpr ,
1021+ IMX95_PE0_LUT_ACSCTRL , IMX95_PEO_LUT_RWA | i );
1022+ regmap_read (imx_pcie -> iomuxc_gpr , IMX95_PE0_LUT_DATA2 , & data2 );
1023+ if (FIELD_GET (IMX95_PE0_LUT_REQID , data2 ) == rid ) {
1024+ regmap_write (imx_pcie -> iomuxc_gpr ,
1025+ IMX95_PE0_LUT_DATA1 , 0 );
1026+ regmap_write (imx_pcie -> iomuxc_gpr ,
1027+ IMX95_PE0_LUT_DATA2 , 0 );
1028+ regmap_write (imx_pcie -> iomuxc_gpr ,
1029+ IMX95_PE0_LUT_ACSCTRL , i );
1030+
1031+ break ;
1032+ }
1033+ }
1034+ }
1035+
1036+ static int imx_pcie_enable_device (struct pci_host_bridge * bridge ,
1037+ struct pci_dev * pdev )
1038+ {
1039+ struct imx_pcie * imx_pcie = to_imx_pcie (to_dw_pcie_from_pp (bridge -> sysdata ));
1040+ u32 sid_i , sid_m , rid = pci_dev_id (pdev );
1041+ struct device_node * target ;
1042+ struct device * dev ;
1043+ int err_i , err_m ;
1044+ u32 sid = 0 ;
1045+
1046+ dev = imx_pcie -> pci -> dev ;
1047+
1048+ target = NULL ;
1049+ err_i = of_map_id (dev -> of_node , rid , "iommu-map" , "iommu-map-mask" ,
1050+ & target , & sid_i );
1051+ if (target ) {
1052+ of_node_put (target );
1053+ } else {
1054+ /*
1055+ * "target == NULL && err_i == 0" means RID out of map range.
1056+ * Use 1:1 map RID to streamID. Hardware can't support this
1057+ * because the streamID is only 6 bits
1058+ */
1059+ err_i = - EINVAL ;
1060+ }
1061+
1062+ target = NULL ;
1063+ err_m = of_map_id (dev -> of_node , rid , "msi-map" , "msi-map-mask" ,
1064+ & target , & sid_m );
1065+
1066+ /*
1067+ * err_m target
1068+ * 0 NULL RID out of range. Use 1:1 map RID to
1069+ * streamID, Current hardware can't
1070+ * support it, so return -EINVAL.
1071+ * != 0 NULL msi-map does not exist, use built-in MSI
1072+ * 0 != NULL Get correct streamID from RID
1073+ * != 0 != NULL Invalid combination
1074+ */
1075+ if (!err_m && !target )
1076+ return - EINVAL ;
1077+ else if (target )
1078+ of_node_put (target ); /* Find streamID map entry for RID in msi-map */
1079+
1080+ /*
1081+ * msi-map iommu-map
1082+ * N N DWC MSI Ctrl
1083+ * Y Y ITS + SMMU, require the same SID
1084+ * Y N ITS
1085+ * N Y DWC MSI Ctrl + SMMU
1086+ */
1087+ if (err_i && err_m )
1088+ return 0 ;
1089+
1090+ if (!err_i && !err_m ) {
1091+ /*
1092+ * Glue Layer
1093+ * <==========>
1094+ * ┌─────┐ ┌──────────┐
1095+ * │ LUT │ 6-bit streamID │ │
1096+ * │ │─────────────────►│ MSI │
1097+ * └─────┘ 2-bit ctrl ID │ │
1098+ * ┌───────────►│ │
1099+ * (i.MX95) │ │ │
1100+ * 00 PCIe0 │ │ │
1101+ * 01 ENETC │ │ │
1102+ * 10 PCIe1 │ │ │
1103+ * │ └──────────┘
1104+ * The MSI glue layer auto adds 2 bits controller ID ahead of
1105+ * streamID, so mask these 2 bits to get streamID. The
1106+ * IOMMU glue layer doesn't do that.
1107+ */
1108+ if (sid_i != (sid_m & IMX95_SID_MASK )) {
1109+ dev_err (dev , "iommu-map and msi-map entries mismatch!\n" );
1110+ return - EINVAL ;
1111+ }
1112+ }
1113+
1114+ if (!err_i )
1115+ sid = sid_i ;
1116+ else if (!err_m )
1117+ sid = sid_m & IMX95_SID_MASK ;
1118+
1119+ return imx_pcie_add_lut (imx_pcie , rid , sid );
1120+ }
1121+
1122+ static void imx_pcie_disable_device (struct pci_host_bridge * bridge ,
1123+ struct pci_dev * pdev )
1124+ {
1125+ struct imx_pcie * imx_pcie ;
1126+
1127+ imx_pcie = to_imx_pcie (to_dw_pcie_from_pp (bridge -> sysdata ));
1128+ imx_pcie_remove_lut (imx_pcie , pci_dev_id (pdev ));
1129+ }
1130+
9331131static int imx_pcie_host_init (struct dw_pcie_rp * pp )
9341132{
9351133 struct dw_pcie * pci = to_dw_pcie_from_pp (pp );
@@ -946,6 +1144,11 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
9461144 }
9471145 }
9481146
1147+ if (pp -> bridge && imx_check_flag (imx_pcie , IMX_PCIE_FLAG_HAS_LUT )) {
1148+ pp -> bridge -> enable_device = imx_pcie_enable_device ;
1149+ pp -> bridge -> disable_device = imx_pcie_disable_device ;
1150+ }
1151+
9491152 imx_pcie_assert_core_reset (imx_pcie );
9501153
9511154 if (imx_pcie -> drvdata -> init_phy )
@@ -1330,6 +1533,8 @@ static int imx_pcie_probe(struct platform_device *pdev)
13301533 imx_pcie -> pci = pci ;
13311534 imx_pcie -> drvdata = of_device_get_match_data (dev );
13321535
1536+ mutex_init (& imx_pcie -> lock );
1537+
13331538 /* Find the PHY if one is defined, only imx7d uses it */
13341539 np = of_parse_phandle (node , "fsl,imx7d-pcie-phy" , 0 );
13351540 if (np ) {
@@ -1627,7 +1832,8 @@ static const struct imx_pcie_drvdata drvdata[] = {
16271832 },
16281833 [IMX95 ] = {
16291834 .variant = IMX95 ,
1630- .flags = IMX_PCIE_FLAG_HAS_SERDES ,
1835+ .flags = IMX_PCIE_FLAG_HAS_SERDES |
1836+ IMX_PCIE_FLAG_HAS_LUT ,
16311837 .clk_names = imx8mq_clks ,
16321838 .clks_cnt = ARRAY_SIZE (imx8mq_clks ),
16331839 .ltssm_off = IMX95_PE0_GEN_CTRL_3 ,
0 commit comments