1818 * Author: Marc Zyngier <[email protected] > 1919 */
2020
21+ #include <linux/bitfield.h>
2122#include <linux/gpio/consumer.h>
2223#include <linux/kernel.h>
2324#include <linux/iopoll.h>
2930#include <linux/of_irq.h>
3031#include <linux/pci-ecam.h>
3132
33+ /* T8103 (original M1) and related SoCs */
3234#define CORE_RC_PHYIF_CTL 0x00024
3335#define CORE_RC_PHYIF_CTL_RUN BIT(0)
3436#define CORE_RC_PHYIF_STAT 0x00028
104106#define PORT_REFCLK_CGDIS BIT(8)
105107#define PORT_PERST 0x00814
106108#define PORT_PERST_OFF BIT(0)
107- #define PORT_RID2SID ( i16 ) ( 0x00828 + 4 * (i16))
109+ #define PORT_RID2SID 0x00828
108110#define PORT_RID2SID_VALID BIT(31)
109111#define PORT_RID2SID_SID_SHIFT 16
110112#define PORT_RID2SID_BUS_SHIFT 8
122124#define PORT_TUNSTAT_PERST_ACK_PEND BIT(1)
123125#define PORT_PREFMEM_ENABLE 0x00994
124126
125- #define MAX_RID2SID 64
127+ #define PORT_MSIMAP_ENABLE BIT(31)
128+ #define PORT_MSIMAP_TARGET GENMASK(7, 0)
126129
127130/*
128131 * The doorbell address is set to 0xfffff000, which by convention
133136 */
134137#define DOORBELL_ADDR CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR
135138
139+ struct hw_info {
140+ u32 phy_lane_ctl ;
141+ u32 port_msiaddr ;
142+ u32 port_msiaddr_hi ;
143+ u32 port_refclk ;
144+ u32 port_perst ;
145+ u32 port_rid2sid ;
146+ u32 port_msimap ;
147+ u32 max_rid2sid ;
148+ };
149+
150+ static const struct hw_info t8103_hw = {
151+ .phy_lane_ctl = PHY_LANE_CTL ,
152+ .port_msiaddr = PORT_MSIADDR ,
153+ .port_msiaddr_hi = 0 ,
154+ .port_refclk = PORT_REFCLK ,
155+ .port_perst = PORT_PERST ,
156+ .port_rid2sid = PORT_RID2SID ,
157+ .port_msimap = 0 ,
158+ .max_rid2sid = 64 ,
159+ };
160+
136161struct apple_pcie {
137162 struct mutex lock ;
138163 struct device * dev ;
139164 void __iomem * base ;
165+ const struct hw_info * hw ;
140166 struct irq_domain * domain ;
141167 unsigned long * bitmap ;
142168 struct list_head ports ;
@@ -380,7 +406,9 @@ static void apple_port_irq_handler(struct irq_desc *desc)
380406static int apple_pcie_port_setup_irq (struct apple_pcie_port * port )
381407{
382408 struct fwnode_handle * fwnode = & port -> np -> fwnode ;
409+ struct apple_pcie * pcie = port -> pcie ;
383410 unsigned int irq ;
411+ u32 val = 0 ;
384412
385413 /* FIXME: consider moving each interrupt under each port */
386414 irq = irq_of_parse_and_map (to_of_node (dev_fwnode (port -> pcie -> dev )),
@@ -402,13 +430,23 @@ static int apple_pcie_port_setup_irq(struct apple_pcie_port *port)
402430
403431 /* Configure MSI base address */
404432 BUILD_BUG_ON (upper_32_bits (DOORBELL_ADDR ));
405- writel_relaxed (lower_32_bits (DOORBELL_ADDR ), port -> base + PORT_MSIADDR );
433+ writel_relaxed (lower_32_bits (DOORBELL_ADDR ),
434+ port -> base + pcie -> hw -> port_msiaddr );
435+ if (pcie -> hw -> port_msiaddr_hi )
436+ writel_relaxed (0 , port -> base + pcie -> hw -> port_msiaddr_hi );
406437
407438 /* Enable MSIs, shared between all ports */
408- writel_relaxed (0 , port -> base + PORT_MSIBASE );
409- writel_relaxed ((ilog2 (port -> pcie -> nvecs ) << PORT_MSICFG_L2MSINUM_SHIFT ) |
410- PORT_MSICFG_EN , port -> base + PORT_MSICFG );
439+ if (pcie -> hw -> port_msimap ) {
440+ for (int i = 0 ; i < pcie -> nvecs ; i ++ )
441+ writel_relaxed (FIELD_PREP (PORT_MSIMAP_TARGET , i ) |
442+ PORT_MSIMAP_ENABLE ,
443+ port -> base + pcie -> hw -> port_msimap + 4 * i );
444+ } else {
445+ writel_relaxed (0 , port -> base + PORT_MSIBASE );
446+ val = ilog2 (pcie -> nvecs ) << PORT_MSICFG_L2MSINUM_SHIFT ;
447+ }
411448
449+ writel_relaxed (val | PORT_MSICFG_EN , port -> base + PORT_MSICFG );
412450 return 0 ;
413451}
414452
@@ -475,7 +513,9 @@ static int apple_pcie_setup_refclk(struct apple_pcie *pcie,
475513 u32 stat ;
476514 int res ;
477515
478- rmw_set (PHY_LANE_CTL_CFGACC , port -> phy + PHY_LANE_CTL );
516+ if (pcie -> hw -> phy_lane_ctl )
517+ rmw_set (PHY_LANE_CTL_CFGACC , port -> phy + pcie -> hw -> phy_lane_ctl );
518+
479519 rmw_set (PHY_LANE_CFG_REFCLK0REQ , port -> phy + PHY_LANE_CFG );
480520
481521 res = readl_relaxed_poll_timeout (port -> phy + PHY_LANE_CFG ,
@@ -492,20 +532,28 @@ static int apple_pcie_setup_refclk(struct apple_pcie *pcie,
492532 if (res < 0 )
493533 return res ;
494534
495- rmw_clear (PHY_LANE_CTL_CFGACC , port -> phy + PHY_LANE_CTL );
535+ if (pcie -> hw -> phy_lane_ctl )
536+ rmw_clear (PHY_LANE_CTL_CFGACC , port -> phy + pcie -> hw -> phy_lane_ctl );
496537
497538 rmw_set (PHY_LANE_CFG_REFCLKEN , port -> phy + PHY_LANE_CFG );
498- rmw_set (PORT_REFCLK_EN , port -> base + PORT_REFCLK );
539+
540+ if (pcie -> hw -> port_refclk )
541+ rmw_set (PORT_REFCLK_EN , port -> base + pcie -> hw -> port_refclk );
499542
500543 return 0 ;
501544}
502545
546+ static void __iomem * port_rid2sid_addr (struct apple_pcie_port * port , int idx )
547+ {
548+ return port -> base + port -> pcie -> hw -> port_rid2sid + 4 * idx ;
549+ }
550+
503551static u32 apple_pcie_rid2sid_write (struct apple_pcie_port * port ,
504552 int idx , u32 val )
505553{
506- writel_relaxed (val , port -> base + PORT_RID2SID ( idx ));
554+ writel_relaxed (val , port_rid2sid_addr ( port , idx ));
507555 /* Read back to ensure completion of the write */
508- return readl_relaxed (port -> base + PORT_RID2SID ( idx ));
556+ return readl_relaxed (port_rid2sid_addr ( port , idx ));
509557}
510558
511559static int apple_pcie_setup_port (struct apple_pcie * pcie ,
@@ -528,7 +576,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
528576 if (!port )
529577 return - ENOMEM ;
530578
531- port -> sid_map = devm_bitmap_zalloc (pcie -> dev , MAX_RID2SID , GFP_KERNEL );
579+ port -> sid_map = devm_bitmap_zalloc (pcie -> dev , pcie -> hw -> max_rid2sid , GFP_KERNEL );
532580 if (!port -> sid_map )
533581 return - ENOMEM ;
534582
@@ -572,7 +620,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
572620 usleep_range (100 , 200 );
573621
574622 /* Deassert PERST# */
575- rmw_set (PORT_PERST_OFF , port -> base + PORT_PERST );
623+ rmw_set (PORT_PERST_OFF , port -> base + pcie -> hw -> port_perst );
576624 gpiod_set_value_cansleep (reset , 0 );
577625
578626 /* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
@@ -585,15 +633,19 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
585633 return ret ;
586634 }
587635
588- rmw_clear (PORT_REFCLK_CGDIS , port -> base + PORT_REFCLK );
636+ if (pcie -> hw -> port_refclk )
637+ rmw_clear (PORT_REFCLK_CGDIS , port -> base + pcie -> hw -> port_refclk );
638+ else
639+ rmw_set (PHY_LANE_CFG_REFCLKCGEN , port -> phy + PHY_LANE_CFG );
640+
589641 rmw_clear (PORT_APPCLK_CGDIS , port -> base + PORT_APPCLK );
590642
591643 ret = apple_pcie_port_setup_irq (port );
592644 if (ret )
593645 return ret ;
594646
595647 /* Reset all RID/SID mappings, and check for RAZ/WI registers */
596- for (i = 0 ; i < MAX_RID2SID ; i ++ ) {
648+ for (i = 0 ; i < pcie -> hw -> max_rid2sid ; i ++ ) {
597649 if (apple_pcie_rid2sid_write (port , i , 0xbad1d ) != 0xbad1d )
598650 break ;
599651 apple_pcie_rid2sid_write (port , i , 0 );
@@ -741,7 +793,7 @@ static void apple_pcie_disable_device(struct pci_host_bridge *bridge, struct pci
741793 for_each_set_bit (idx , port -> sid_map , port -> sid_map_sz ) {
742794 u32 val ;
743795
744- val = readl_relaxed (port -> base + PORT_RID2SID ( idx ));
796+ val = readl_relaxed (port_rid2sid_addr ( port , idx ));
745797 if ((val & 0xffff ) == rid ) {
746798 apple_pcie_rid2sid_write (port , idx , 0 );
747799 bitmap_release_region (port -> sid_map , idx , 0 );
@@ -792,6 +844,9 @@ static int apple_pcie_probe(struct platform_device *pdev)
792844 return - ENOMEM ;
793845
794846 pcie -> dev = dev ;
847+ pcie -> hw = of_device_get_match_data (dev );
848+ if (!pcie -> hw )
849+ return - ENODEV ;
795850 pcie -> base = devm_platform_ioremap_resource (pdev , 1 );
796851 if (IS_ERR (pcie -> base ))
797852 return PTR_ERR (pcie -> base );
@@ -808,7 +863,7 @@ static int apple_pcie_probe(struct platform_device *pdev)
808863}
809864
810865static const struct of_device_id apple_pcie_of_match [] = {
811- { .compatible = "apple,pcie" },
866+ { .compatible = "apple,pcie" , . data = & t8103_hw },
812867 { }
813868};
814869MODULE_DEVICE_TABLE (of , apple_pcie_of_match );
0 commit comments