29
29
#include <linux/types.h>
30
30
#include <linux/interrupt.h>
31
31
#include <linux/reset.h>
32
+ #include <linux/phy/phy.h>
32
33
#include <linux/pm_domain.h>
33
34
#include <linux/pm_runtime.h>
34
35
@@ -49,6 +50,7 @@ enum imx6_pcie_variants {
49
50
IMX6QP ,
50
51
IMX7D ,
51
52
IMX8MQ ,
53
+ IMX8MM ,
52
54
};
53
55
54
56
#define IMX6_PCIE_FLAG_IMX6_PHY BIT(0)
@@ -88,6 +90,7 @@ struct imx6_pcie {
88
90
struct device * pd_pcie ;
89
91
/* power domain for pcie phy */
90
92
struct device * pd_pcie_phy ;
93
+ struct phy * phy ;
91
94
const struct imx6_pcie_drvdata * drvdata ;
92
95
};
93
96
@@ -372,6 +375,8 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
372
375
case IMX7D :
373
376
case IMX8MQ :
374
377
reset_control_assert (imx6_pcie -> pciephy_reset );
378
+ fallthrough ;
379
+ case IMX8MM :
375
380
reset_control_assert (imx6_pcie -> apps_reset );
376
381
break ;
377
382
case IMX6SX :
@@ -407,7 +412,8 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
407
412
408
413
static unsigned int imx6_pcie_grp_offset (const struct imx6_pcie * imx6_pcie )
409
414
{
410
- WARN_ON (imx6_pcie -> drvdata -> variant != IMX8MQ );
415
+ WARN_ON (imx6_pcie -> drvdata -> variant != IMX8MQ &&
416
+ imx6_pcie -> drvdata -> variant != IMX8MM );
411
417
return imx6_pcie -> controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14 ;
412
418
}
413
419
@@ -446,6 +452,11 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
446
452
break ;
447
453
case IMX7D :
448
454
break ;
455
+ case IMX8MM :
456
+ ret = clk_prepare_enable (imx6_pcie -> pcie_aux );
457
+ if (ret )
458
+ dev_err (dev , "unable to enable pcie_aux clock\n" );
459
+ break ;
449
460
case IMX8MQ :
450
461
ret = clk_prepare_enable (imx6_pcie -> pcie_aux );
451
462
if (ret ) {
@@ -522,6 +533,14 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
522
533
goto err_ref_clk ;
523
534
}
524
535
536
+ switch (imx6_pcie -> drvdata -> variant ) {
537
+ case IMX8MM :
538
+ if (phy_power_on (imx6_pcie -> phy ))
539
+ dev_err (dev , "unable to power on PHY\n" );
540
+ break ;
541
+ default :
542
+ break ;
543
+ }
525
544
/* allow the clocks to stabilize */
526
545
usleep_range (200 , 500 );
527
546
@@ -538,6 +557,10 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
538
557
case IMX8MQ :
539
558
reset_control_deassert (imx6_pcie -> pciephy_reset );
540
559
break ;
560
+ case IMX8MM :
561
+ if (phy_init (imx6_pcie -> phy ))
562
+ dev_err (dev , "waiting for phy ready timeout!\n" );
563
+ break ;
541
564
case IMX7D :
542
565
reset_control_deassert (imx6_pcie -> pciephy_reset );
543
566
@@ -614,6 +637,12 @@ static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie)
614
637
static void imx6_pcie_init_phy (struct imx6_pcie * imx6_pcie )
615
638
{
616
639
switch (imx6_pcie -> drvdata -> variant ) {
640
+ case IMX8MM :
641
+ /*
642
+ * The PHY initialization had been done in the PHY
643
+ * driver, break here directly.
644
+ */
645
+ break ;
617
646
case IMX8MQ :
618
647
/*
619
648
* TODO: Currently this code assumes external
@@ -753,6 +782,7 @@ static void imx6_pcie_ltssm_enable(struct device *dev)
753
782
break ;
754
783
case IMX7D :
755
784
case IMX8MQ :
785
+ case IMX8MM :
756
786
reset_control_deassert (imx6_pcie -> apps_reset );
757
787
break ;
758
788
}
@@ -871,6 +901,7 @@ static void imx6_pcie_ltssm_disable(struct device *dev)
871
901
IMX6Q_GPR12_PCIE_CTL_2 , 0 );
872
902
break ;
873
903
case IMX7D :
904
+ case IMX8MM :
874
905
reset_control_assert (imx6_pcie -> apps_reset );
875
906
break ;
876
907
default :
@@ -930,6 +961,7 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
930
961
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL );
931
962
break ;
932
963
case IMX8MQ :
964
+ case IMX8MM :
933
965
clk_disable_unprepare (imx6_pcie -> pcie_aux );
934
966
break ;
935
967
default :
@@ -945,8 +977,16 @@ static int imx6_pcie_suspend_noirq(struct device *dev)
945
977
return 0 ;
946
978
947
979
imx6_pcie_pm_turnoff (imx6_pcie );
948
- imx6_pcie_clk_disable (imx6_pcie );
949
980
imx6_pcie_ltssm_disable (dev );
981
+ imx6_pcie_clk_disable (imx6_pcie );
982
+ switch (imx6_pcie -> drvdata -> variant ) {
983
+ case IMX8MM :
984
+ if (phy_power_off (imx6_pcie -> phy ))
985
+ dev_err (dev , "unable to power off PHY\n" );
986
+ break ;
987
+ default :
988
+ break ;
989
+ }
950
990
951
991
return 0 ;
952
992
}
@@ -1043,11 +1083,6 @@ static int imx6_pcie_probe(struct platform_device *pdev)
1043
1083
}
1044
1084
1045
1085
/* Fetch clocks */
1046
- imx6_pcie -> pcie_phy = devm_clk_get (dev , "pcie_phy" );
1047
- if (IS_ERR (imx6_pcie -> pcie_phy ))
1048
- return dev_err_probe (dev , PTR_ERR (imx6_pcie -> pcie_phy ),
1049
- "pcie_phy clock source missing or invalid\n" );
1050
-
1051
1086
imx6_pcie -> pcie_bus = devm_clk_get (dev , "pcie_bus" );
1052
1087
if (IS_ERR (imx6_pcie -> pcie_bus ))
1053
1088
return dev_err_probe (dev , PTR_ERR (imx6_pcie -> pcie_bus ),
@@ -1089,10 +1124,35 @@ static int imx6_pcie_probe(struct platform_device *pdev)
1089
1124
dev_err (dev , "Failed to get PCIE APPS reset control\n" );
1090
1125
return PTR_ERR (imx6_pcie -> apps_reset );
1091
1126
}
1127
+ break ;
1128
+ case IMX8MM :
1129
+ imx6_pcie -> pcie_aux = devm_clk_get (dev , "pcie_aux" );
1130
+ if (IS_ERR (imx6_pcie -> pcie_aux ))
1131
+ return dev_err_probe (dev , PTR_ERR (imx6_pcie -> pcie_aux ),
1132
+ "pcie_aux clock source missing or invalid\n" );
1133
+ imx6_pcie -> apps_reset = devm_reset_control_get_exclusive (dev ,
1134
+ "apps" );
1135
+ if (IS_ERR (imx6_pcie -> apps_reset ))
1136
+ return dev_err_probe (dev , PTR_ERR (imx6_pcie -> apps_reset ),
1137
+ "failed to get pcie apps reset control\n" );
1138
+
1139
+ imx6_pcie -> phy = devm_phy_get (dev , "pcie-phy" );
1140
+ if (IS_ERR (imx6_pcie -> phy ))
1141
+ return dev_err_probe (dev , PTR_ERR (imx6_pcie -> phy ),
1142
+ "failed to get pcie phy\n" );
1143
+
1092
1144
break ;
1093
1145
default :
1094
1146
break ;
1095
1147
}
1148
+ /* Don't fetch the pcie_phy clock, if it has abstract PHY driver */
1149
+ if (imx6_pcie -> phy == NULL ) {
1150
+ imx6_pcie -> pcie_phy = devm_clk_get (dev , "pcie_phy" );
1151
+ if (IS_ERR (imx6_pcie -> pcie_phy ))
1152
+ return dev_err_probe (dev , PTR_ERR (imx6_pcie -> pcie_phy ),
1153
+ "pcie_phy clock source missing or invalid\n" );
1154
+ }
1155
+
1096
1156
1097
1157
/* Grab turnoff reset */
1098
1158
imx6_pcie -> turnoff_reset = devm_reset_control_get_optional_exclusive (dev , "turnoff" );
@@ -1202,14 +1262,19 @@ static const struct imx6_pcie_drvdata drvdata[] = {
1202
1262
[IMX8MQ ] = {
1203
1263
.variant = IMX8MQ ,
1204
1264
},
1265
+ [IMX8MM ] = {
1266
+ .variant = IMX8MM ,
1267
+ .flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND ,
1268
+ },
1205
1269
};
1206
1270
1207
1271
static const struct of_device_id imx6_pcie_of_match [] = {
1208
1272
{ .compatible = "fsl,imx6q-pcie" , .data = & drvdata [IMX6Q ], },
1209
1273
{ .compatible = "fsl,imx6sx-pcie" , .data = & drvdata [IMX6SX ], },
1210
1274
{ .compatible = "fsl,imx6qp-pcie" , .data = & drvdata [IMX6QP ], },
1211
1275
{ .compatible = "fsl,imx7d-pcie" , .data = & drvdata [IMX7D ], },
1212
- { .compatible = "fsl,imx8mq-pcie" , .data = & drvdata [IMX8MQ ], } ,
1276
+ { .compatible = "fsl,imx8mq-pcie" , .data = & drvdata [IMX8MQ ], },
1277
+ { .compatible = "fsl,imx8mm-pcie" , .data = & drvdata [IMX8MM ], },
1213
1278
{},
1214
1279
};
1215
1280
0 commit comments