Skip to content

Commit 22cc698

Browse files
marcanjannau
authored andcommitted
PCIE: apple: Add T602x PCIe support
This version of the hardware moved around a bunch of registers, so we drop the old compatible for these and introduce register offset structures to handle the differences. Signed-off-by: Hector Martin <marcan@marcan.st>
1 parent f19bf96 commit 22cc698

1 file changed

Lines changed: 106 additions & 21 deletions

File tree

drivers/pci/controller/pcie-apple.c

Lines changed: 106 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/module.h>
2828
#include <linux/msi.h>
2929
#include <linux/notifier.h>
30+
#include <linux/of_device.h>
3031
#include <linux/of_irq.h>
3132
#include <linux/pci-ecam.h>
3233

@@ -105,7 +106,7 @@
105106
#define PORT_REFCLK_CGDIS BIT(8)
106107
#define PORT_PERST 0x00814
107108
#define PORT_PERST_OFF BIT(0)
108-
#define PORT_RID2SID(i16) (0x00828 + 4 * (i16))
109+
#define PORT_RID2SID 0x00828
109110
#define PORT_RID2SID_VALID BIT(31)
110111
#define PORT_RID2SID_SID_SHIFT 16
111112
#define PORT_RID2SID_BUS_SHIFT 8
@@ -123,7 +124,7 @@
123124
#define PORT_TUNSTAT_PERST_ACK_PEND BIT(1)
124125
#define PORT_PREFMEM_ENABLE 0x00994
125126

126-
#define MAX_RID2SID 64
127+
#define MAX_RID2SID 512
127128

128129
/*
129130
* The doorbell address is set to 0xfffff000, which by convention
@@ -134,6 +135,57 @@
134135
*/
135136
#define DOORBELL_ADDR CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR
136137

138+
struct reg_info {
139+
u32 phy_lane_ctl;
140+
u32 port_msiaddr;
141+
u32 port_msiaddr_hi;
142+
u32 port_refclk;
143+
u32 port_perst;
144+
u32 port_rid2sid;
145+
u32 port_msimap;
146+
u32 max_rid2sid;
147+
u32 max_msimap;
148+
};
149+
150+
const struct reg_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+
.max_msimap = 0,
160+
};
161+
162+
#define PORT_T602X_MSIADDR 0x016c
163+
#define PORT_T602X_MSIADDR_HI 0x0170
164+
#define PORT_T602X_PERST 0x082c
165+
#define PORT_T602X_RID2SID 0x3000
166+
#define PORT_T602X_MSIMAP 0x3800
167+
168+
#define PORT_MSIMAP_ENABLE BIT(31)
169+
#define PORT_MSIMAP_TARGET GENMASK(7, 0)
170+
171+
const struct reg_info t602x_hw = {
172+
.phy_lane_ctl = 0,
173+
.port_msiaddr = PORT_T602X_MSIADDR,
174+
.port_msiaddr_hi = PORT_T602X_MSIADDR_HI,
175+
.port_refclk = 0,
176+
.port_perst = PORT_T602X_PERST,
177+
.port_rid2sid = PORT_T602X_RID2SID,
178+
.port_msimap = PORT_T602X_MSIMAP,
179+
.max_rid2sid = 512, /* 16 on t602x, guess for autodetect on future HW */
180+
.max_msimap = 512, /* 96 on t602x, guess for autodetect on future HW */
181+
};
182+
183+
static const struct of_device_id apple_pcie_of_match_hw[] = {
184+
{ .compatible = "apple,t6020-pcie", .data = &t602x_hw },
185+
{ .compatible = "apple,pcie", .data = &t8103_hw },
186+
{ }
187+
};
188+
137189
struct apple_pcie {
138190
struct mutex lock;
139191
struct device *dev;
@@ -144,6 +196,7 @@ struct apple_pcie {
144196
struct completion event;
145197
struct irq_fwspec fwspec;
146198
u32 nvecs;
199+
const struct reg_info *hw;
147200
};
148201

149202
struct apple_pcie_port {
@@ -267,14 +320,14 @@ static void apple_port_irq_mask(struct irq_data *data)
267320
{
268321
struct apple_pcie_port *port = irq_data_get_irq_chip_data(data);
269322

270-
writel_relaxed(BIT(data->hwirq), port->base + PORT_INTMSKSET);
323+
rmw_set(BIT(data->hwirq), port->base + PORT_INTMSK);
271324
}
272325

273326
static void apple_port_irq_unmask(struct irq_data *data)
274327
{
275328
struct apple_pcie_port *port = irq_data_get_irq_chip_data(data);
276329

277-
writel_relaxed(BIT(data->hwirq), port->base + PORT_INTMSKCLR);
330+
rmw_clear(BIT(data->hwirq), port->base + PORT_INTMSK);
278331
}
279332

280333
static bool hwirq_is_intx(unsigned int hwirq)
@@ -378,6 +431,7 @@ static void apple_port_irq_handler(struct irq_desc *desc)
378431
static int apple_pcie_port_setup_irq(struct apple_pcie_port *port)
379432
{
380433
struct fwnode_handle *fwnode = &port->np->fwnode;
434+
struct apple_pcie *pcie = port->pcie;
381435
unsigned int irq;
382436

383437
/* FIXME: consider moving each interrupt under each port */
@@ -393,19 +447,35 @@ static int apple_pcie_port_setup_irq(struct apple_pcie_port *port)
393447
return -ENOMEM;
394448

395449
/* Disable all interrupts */
396-
writel_relaxed(~0, port->base + PORT_INTMSKSET);
450+
writel_relaxed(~0, port->base + PORT_INTMSK);
397451
writel_relaxed(~0, port->base + PORT_INTSTAT);
452+
writel_relaxed(~0, port->base + PORT_LINKCMDSTS);
398453

399454
irq_set_chained_handler_and_data(irq, apple_port_irq_handler, port);
400455

401456
/* Configure MSI base address */
402-
BUILD_BUG_ON(upper_32_bits(DOORBELL_ADDR));
403-
writel_relaxed(lower_32_bits(DOORBELL_ADDR), port->base + PORT_MSIADDR);
457+
BUG_ON(upper_32_bits(DOORBELL_ADDR));
458+
writel_relaxed(lower_32_bits(DOORBELL_ADDR),
459+
port->base + pcie->hw->port_msiaddr);
460+
if (pcie->hw->port_msiaddr_hi)
461+
writel_relaxed(0, port->base + pcie->hw->port_msiaddr_hi);
404462

405463
/* Enable MSIs, shared between all ports */
406-
writel_relaxed(0, port->base + PORT_MSIBASE);
407-
writel_relaxed((ilog2(port->pcie->nvecs) << PORT_MSICFG_L2MSINUM_SHIFT) |
408-
PORT_MSICFG_EN, port->base + PORT_MSICFG);
464+
if (pcie->hw->port_msimap) {
465+
int i;
466+
467+
for (i = 0; i < pcie->nvecs; i++) {
468+
writel_relaxed(FIELD_PREP(PORT_MSIMAP_TARGET, i) |
469+
PORT_MSIMAP_ENABLE,
470+
port->base + pcie->hw->port_msimap + 4 * i);
471+
}
472+
473+
writel_relaxed(PORT_MSICFG_EN, port->base + PORT_MSICFG);
474+
} else {
475+
writel_relaxed(0, port->base + PORT_MSIBASE);
476+
writel_relaxed((ilog2(pcie->nvecs) << PORT_MSICFG_L2MSINUM_SHIFT) |
477+
PORT_MSICFG_EN, port->base + PORT_MSICFG);
478+
}
409479

410480
return 0;
411481
}
@@ -473,7 +543,9 @@ static int apple_pcie_setup_refclk(struct apple_pcie *pcie,
473543
u32 stat;
474544
int res;
475545

476-
rmw_set(PHY_LANE_CTL_CFGACC, port->phy + PHY_LANE_CTL);
546+
if (pcie->hw->phy_lane_ctl)
547+
rmw_set(PHY_LANE_CTL_CFGACC, port->phy + pcie->hw->phy_lane_ctl);
548+
477549
rmw_set(PHY_LANE_CFG_REFCLK0REQ, port->phy + PHY_LANE_CFG);
478550

479551
res = readl_relaxed_poll_timeout(port->phy + PHY_LANE_CFG,
@@ -490,20 +562,23 @@ static int apple_pcie_setup_refclk(struct apple_pcie *pcie,
490562
if (res < 0)
491563
return res;
492564

493-
rmw_clear(PHY_LANE_CTL_CFGACC, port->phy + PHY_LANE_CTL);
565+
if (pcie->hw->phy_lane_ctl)
566+
rmw_clear(PHY_LANE_CTL_CFGACC, port->phy + pcie->hw->phy_lane_ctl);
494567

495568
rmw_set(PHY_LANE_CFG_REFCLKEN, port->phy + PHY_LANE_CFG);
496-
rmw_set(PORT_REFCLK_EN, port->base + PORT_REFCLK);
569+
570+
if (pcie->hw->port_refclk)
571+
rmw_set(PORT_REFCLK_EN, port->base + pcie->hw->port_refclk);
497572

498573
return 0;
499574
}
500575

501576
static u32 apple_pcie_rid2sid_write(struct apple_pcie_port *port,
502577
int idx, u32 val)
503578
{
504-
writel_relaxed(val, port->base + PORT_RID2SID(idx));
579+
writel_relaxed(val, port->base + port->pcie->hw->port_rid2sid + 4 * idx);
505580
/* Read back to ensure completion of the write */
506-
return readl_relaxed(port->base + PORT_RID2SID(idx));
581+
return readl_relaxed(port->base + port->pcie->hw->port_rid2sid + 4 * idx);
507582
}
508583

509584
static int apple_pcie_probe_port(struct device_node *np)
@@ -602,7 +677,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
602677
usleep_range(100, 200);
603678

604679
/* Deassert PERST# */
605-
rmw_set(PORT_PERST_OFF, port->base + PORT_PERST);
680+
rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst);
606681
gpiod_set_value_cansleep(reset, 0);
607682

608683
/* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
@@ -615,15 +690,12 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
615690
return ret;
616691
}
617692

618-
rmw_clear(PORT_REFCLK_CGDIS, port->base + PORT_REFCLK);
619-
rmw_clear(PORT_APPCLK_CGDIS, port->base + PORT_APPCLK);
620-
621693
ret = apple_pcie_port_setup_irq(port);
622694
if (ret)
623695
return ret;
624696

625697
/* Reset all RID/SID mappings, and check for RAZ/WI registers */
626-
for (i = 0; i < MAX_RID2SID; i++) {
698+
for (i = 0; i < pcie->hw->max_rid2sid; i++) {
627699
if (apple_pcie_rid2sid_write(port, i, 0xbad1d) != 0xbad1d)
628700
break;
629701
apple_pcie_rid2sid_write(port, i, 0);
@@ -647,6 +719,12 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
647719
if (!wait_for_completion_timeout(&pcie->event, HZ / 10))
648720
dev_warn(pcie->dev, "%pOF link didn't come up\n", np);
649721

722+
if (pcie->hw->port_refclk)
723+
rmw_clear(PORT_REFCLK_CGDIS, port->base + PORT_REFCLK);
724+
else
725+
rmw_set(PHY_LANE_CFG_REFCLKCGEN, port->phy + PHY_LANE_CFG);
726+
rmw_clear(PORT_APPCLK_CGDIS, port->base + PORT_APPCLK);
727+
650728
return 0;
651729
}
652730

@@ -763,7 +841,7 @@ static void apple_pcie_release_device(struct apple_pcie_port *port,
763841
for_each_set_bit(idx, port->sid_map, port->sid_map_sz) {
764842
u32 val;
765843

766-
val = readl_relaxed(port->base + PORT_RID2SID(idx));
844+
val = readl_relaxed(port->base + port->pcie->hw->port_rid2sid + 4 * idx);
767845
if ((val & 0xffff) == rid) {
768846
apple_pcie_rid2sid_write(port, idx, 0);
769847
bitmap_release_region(port->sid_map, idx, 0);
@@ -820,13 +898,19 @@ static int apple_pcie_init(struct pci_config_window *cfg)
820898
struct platform_device *platform = to_platform_device(dev);
821899
struct device_node *of_port;
822900
struct apple_pcie *pcie;
901+
const struct of_device_id *match;
823902
int ret;
824903

904+
match = of_match_device(apple_pcie_of_match_hw, dev);
905+
if (!match)
906+
return -ENODEV;
907+
825908
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
826909
if (!pcie)
827910
return -ENOMEM;
828911

829912
pcie->dev = dev;
913+
pcie->hw = match->data;
830914

831915
mutex_init(&pcie->lock);
832916

@@ -889,6 +973,7 @@ static const struct pci_ecam_ops apple_pcie_cfg_ecam_ops = {
889973
};
890974

891975
static const struct of_device_id apple_pcie_of_match[] = {
976+
{ .compatible = "apple,t6020-pcie", .data = &apple_pcie_cfg_ecam_ops },
892977
{ .compatible = "apple,pcie", .data = &apple_pcie_cfg_ecam_ops },
893978
{ }
894979
};

0 commit comments

Comments
 (0)