1919#include <linux/of_platform.h>
2020#include <linux/pci.h>
2121#include <linux/pci-ecam.h>
22+ #include <linux/phy/phy.h>
2223#include <linux/platform_device.h>
2324#include <linux/irqchip/chained_irq.h>
2425
@@ -157,6 +158,7 @@ struct nwl_pcie {
157158 void __iomem * breg_base ;
158159 void __iomem * pcireg_base ;
159160 void __iomem * ecam_base ;
161+ struct phy * phy [4 ];
160162 phys_addr_t phys_breg_base ; /* Physical Bridge Register Base */
161163 phys_addr_t phys_pcie_reg_base ; /* Physical PCIe Controller Base */
162164 phys_addr_t phys_ecam_base ; /* Physical Configuration Base */
@@ -521,6 +523,60 @@ static int nwl_pcie_init_msi_irq_domain(struct nwl_pcie *pcie)
521523 return 0 ;
522524}
523525
526+ static void nwl_pcie_phy_power_off (struct nwl_pcie * pcie , int i )
527+ {
528+ int err = phy_power_off (pcie -> phy [i ]);
529+
530+ if (err )
531+ dev_err (pcie -> dev , "could not power off phy %d (err=%d)\n" , i ,
532+ err );
533+ }
534+
535+ static void nwl_pcie_phy_exit (struct nwl_pcie * pcie , int i )
536+ {
537+ int err = phy_exit (pcie -> phy [i ]);
538+
539+ if (err )
540+ dev_err (pcie -> dev , "could not exit phy %d (err=%d)\n" , i , err );
541+ }
542+
543+ static int nwl_pcie_phy_enable (struct nwl_pcie * pcie )
544+ {
545+ int i , ret ;
546+
547+ for (i = 0 ; i < ARRAY_SIZE (pcie -> phy ); i ++ ) {
548+ ret = phy_init (pcie -> phy [i ]);
549+ if (ret )
550+ goto err ;
551+
552+ ret = phy_power_on (pcie -> phy [i ]);
553+ if (ret ) {
554+ nwl_pcie_phy_exit (pcie , i );
555+ goto err ;
556+ }
557+ }
558+
559+ return 0 ;
560+
561+ err :
562+ while (i -- ) {
563+ nwl_pcie_phy_power_off (pcie , i );
564+ nwl_pcie_phy_exit (pcie , i );
565+ }
566+
567+ return ret ;
568+ }
569+
570+ static void nwl_pcie_phy_disable (struct nwl_pcie * pcie )
571+ {
572+ int i ;
573+
574+ for (i = ARRAY_SIZE (pcie -> phy ); i -- ;) {
575+ nwl_pcie_phy_power_off (pcie , i );
576+ nwl_pcie_phy_exit (pcie , i );
577+ }
578+ }
579+
524580static int nwl_pcie_init_irq_domain (struct nwl_pcie * pcie )
525581{
526582 struct device * dev = pcie -> dev ;
@@ -732,6 +788,7 @@ static int nwl_pcie_parse_dt(struct nwl_pcie *pcie,
732788{
733789 struct device * dev = pcie -> dev ;
734790 struct resource * res ;
791+ int i ;
735792
736793 res = platform_get_resource_byname (pdev , IORESOURCE_MEM , "breg" );
737794 pcie -> breg_base = devm_ioremap_resource (dev , res );
@@ -759,6 +816,18 @@ static int nwl_pcie_parse_dt(struct nwl_pcie *pcie,
759816 irq_set_chained_handler_and_data (pcie -> irq_intx ,
760817 nwl_pcie_leg_handler , pcie );
761818
819+
820+ for (i = 0 ; i < ARRAY_SIZE (pcie -> phy ); i ++ ) {
821+ pcie -> phy [i ] = devm_of_phy_get_by_index (dev , dev -> of_node , i );
822+ if (PTR_ERR (pcie -> phy [i ]) == - ENODEV ) {
823+ pcie -> phy [i ] = NULL ;
824+ break ;
825+ }
826+
827+ if (IS_ERR (pcie -> phy [i ]))
828+ return PTR_ERR (pcie -> phy [i ]);
829+ }
830+
762831 return 0 ;
763832}
764833
@@ -799,16 +868,22 @@ static int nwl_pcie_probe(struct platform_device *pdev)
799868 return err ;
800869 }
801870
871+ err = nwl_pcie_phy_enable (pcie );
872+ if (err ) {
873+ dev_err (dev , "could not enable PHYs\n" );
874+ goto err_clk ;
875+ }
876+
802877 err = nwl_pcie_bridge_init (pcie );
803878 if (err ) {
804879 dev_err (dev , "HW Initialization failed\n" );
805- goto err_clk ;
880+ goto err_phy ;
806881 }
807882
808883 err = nwl_pcie_init_irq_domain (pcie );
809884 if (err ) {
810885 dev_err (dev , "Failed creating IRQ Domain\n" );
811- goto err_clk ;
886+ goto err_phy ;
812887 }
813888
814889 bridge -> sysdata = pcie ;
@@ -818,14 +893,16 @@ static int nwl_pcie_probe(struct platform_device *pdev)
818893 err = nwl_pcie_enable_msi (pcie );
819894 if (err < 0 ) {
820895 dev_err (dev , "failed to enable MSI support: %d\n" , err );
821- goto err_clk ;
896+ goto err_phy ;
822897 }
823898 }
824899
825900 err = pci_host_probe (bridge );
826901 if (!err )
827902 return 0 ;
828903
904+ err_phy :
905+ nwl_pcie_phy_disable (pcie );
829906err_clk :
830907 clk_disable_unprepare (pcie -> clk );
831908 return err ;
@@ -835,6 +912,7 @@ static void nwl_pcie_remove(struct platform_device *pdev)
835912{
836913 struct nwl_pcie * pcie = platform_get_drvdata (pdev );
837914
915+ nwl_pcie_phy_disable (pcie );
838916 clk_disable_unprepare (pcie -> clk );
839917}
840918
0 commit comments