Skip to content

Commit 60f2ee5

Browse files
sharathkumardmkwilczynski
authored andcommitted
PCI: altera: Add Agilex support
Add PCIe Root Port controller support for the Agilex family of chips. The Agilex PCIe Hard IP has three variants that are mostly software compatible, except for a couple register offsets. The P-Tile variant supports Gen3/Gen4 1x16. The F-Tile variant supports Gen3/Gen4 4x4, 4x8, and 4x16. The R-Tile variant improves on the F-Tile variant by adding Gen5 support. To simplify the implementation of pci_ops read/write functions, ep_{read/write}_cfg() callbacks were added to struct altera_pci_ops to easily distinguish between hardware variants. Signed-off-by: D M, Sharath Kumar <[email protected]> Signed-off-by: Matthew Gerlach <[email protected]> Reviewed-by: Manivannan Sadhasivam <[email protected]> Link: https://lore.kernel.org/r/[email protected] [kwilczynski: tidy code comments] Signed-off-by: Krzysztof Wilczyński <[email protected]>
1 parent 6843f38 commit 60f2ee5

File tree

1 file changed

+246
-9
lines changed

1 file changed

+246
-9
lines changed

drivers/pci/controller/pcie-altera.c

Lines changed: 246 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* Description: Altera PCIe host controller driver
77
*/
88

9+
#include <linux/bitfield.h>
910
#include <linux/delay.h>
1011
#include <linux/interrupt.h>
1112
#include <linux/irqchip/chained_irq.h>
@@ -77,9 +78,25 @@
7778
#define S10_TLP_FMTTYPE_CFGWR0 0x45
7879
#define S10_TLP_FMTTYPE_CFGWR1 0x44
7980

81+
#define AGLX_RP_CFG_ADDR(pcie, reg) (((pcie)->hip_base) + (reg))
82+
#define AGLX_RP_SECONDARY(pcie) \
83+
readb(AGLX_RP_CFG_ADDR(pcie, PCI_SECONDARY_BUS))
84+
85+
#define AGLX_BDF_REG 0x00002004
86+
#define AGLX_ROOT_PORT_IRQ_STATUS 0x14c
87+
#define AGLX_ROOT_PORT_IRQ_ENABLE 0x150
88+
#define CFG_AER BIT(4)
89+
90+
#define AGLX_CFG_TARGET GENMASK(13, 12)
91+
#define AGLX_CFG_TARGET_TYPE0 0
92+
#define AGLX_CFG_TARGET_TYPE1 1
93+
#define AGLX_CFG_TARGET_LOCAL_2000 2
94+
#define AGLX_CFG_TARGET_LOCAL_3000 3
95+
8096
enum altera_pcie_version {
8197
ALTERA_PCIE_V1 = 0,
8298
ALTERA_PCIE_V2,
99+
ALTERA_PCIE_V3,
83100
};
84101

85102
struct altera_pcie {
@@ -102,6 +119,11 @@ struct altera_pcie_ops {
102119
int size, u32 *value);
103120
int (*rp_write_cfg)(struct altera_pcie *pcie, u8 busno,
104121
int where, int size, u32 value);
122+
int (*ep_read_cfg)(struct altera_pcie *pcie, u8 busno,
123+
unsigned int devfn, int where, int size, u32 *value);
124+
int (*ep_write_cfg)(struct altera_pcie *pcie, u8 busno,
125+
unsigned int devfn, int where, int size, u32 value);
126+
void (*rp_isr)(struct irq_desc *desc);
105127
};
106128

107129
struct altera_pcie_data {
@@ -112,6 +134,9 @@ struct altera_pcie_data {
112134
u32 cfgrd1;
113135
u32 cfgwr0;
114136
u32 cfgwr1;
137+
u32 port_conf_offset;
138+
u32 port_irq_status_offset;
139+
u32 port_irq_enable_offset;
115140
};
116141

117142
struct tlp_rp_regpair_t {
@@ -131,6 +156,28 @@ static inline u32 cra_readl(struct altera_pcie *pcie, const u32 reg)
131156
return readl_relaxed(pcie->cra_base + reg);
132157
}
133158

159+
static inline void cra_writew(struct altera_pcie *pcie, const u32 value,
160+
const u32 reg)
161+
{
162+
writew_relaxed(value, pcie->cra_base + reg);
163+
}
164+
165+
static inline u32 cra_readw(struct altera_pcie *pcie, const u32 reg)
166+
{
167+
return readw_relaxed(pcie->cra_base + reg);
168+
}
169+
170+
static inline void cra_writeb(struct altera_pcie *pcie, const u32 value,
171+
const u32 reg)
172+
{
173+
writeb_relaxed(value, pcie->cra_base + reg);
174+
}
175+
176+
static inline u32 cra_readb(struct altera_pcie *pcie, const u32 reg)
177+
{
178+
return readb_relaxed(pcie->cra_base + reg);
179+
}
180+
134181
static bool altera_pcie_link_up(struct altera_pcie *pcie)
135182
{
136183
return !!((cra_readl(pcie, RP_LTSSM) & RP_LTSSM_MASK) == LTSSM_L0);
@@ -145,6 +192,15 @@ static bool s10_altera_pcie_link_up(struct altera_pcie *pcie)
145192
return !!(readw(addr) & PCI_EXP_LNKSTA_DLLLA);
146193
}
147194

195+
static bool aglx_altera_pcie_link_up(struct altera_pcie *pcie)
196+
{
197+
void __iomem *addr = AGLX_RP_CFG_ADDR(pcie,
198+
pcie->pcie_data->cap_offset +
199+
PCI_EXP_LNKSTA);
200+
201+
return (readw_relaxed(addr) & PCI_EXP_LNKSTA_DLLLA);
202+
}
203+
148204
/*
149205
* Altera PCIe port uses BAR0 of RC's configuration space as the translation
150206
* from PCI bus to native BUS. Entire DDR region is mapped into PCIe space
@@ -425,6 +481,103 @@ static int s10_rp_write_cfg(struct altera_pcie *pcie, u8 busno,
425481
return PCIBIOS_SUCCESSFUL;
426482
}
427483

484+
static int aglx_rp_read_cfg(struct altera_pcie *pcie, int where,
485+
int size, u32 *value)
486+
{
487+
void __iomem *addr = AGLX_RP_CFG_ADDR(pcie, where);
488+
489+
switch (size) {
490+
case 1:
491+
*value = readb_relaxed(addr);
492+
break;
493+
case 2:
494+
*value = readw_relaxed(addr);
495+
break;
496+
default:
497+
*value = readl_relaxed(addr);
498+
break;
499+
}
500+
501+
/* Interrupt PIN not programmed in hardware, set to INTA. */
502+
if (where == PCI_INTERRUPT_PIN && size == 1 && !(*value))
503+
*value = 0x01;
504+
else if (where == PCI_INTERRUPT_LINE && !(*value & 0xff00))
505+
*value |= 0x0100;
506+
507+
return PCIBIOS_SUCCESSFUL;
508+
}
509+
510+
static int aglx_rp_write_cfg(struct altera_pcie *pcie, u8 busno,
511+
int where, int size, u32 value)
512+
{
513+
void __iomem *addr = AGLX_RP_CFG_ADDR(pcie, where);
514+
515+
switch (size) {
516+
case 1:
517+
writeb_relaxed(value, addr);
518+
break;
519+
case 2:
520+
writew_relaxed(value, addr);
521+
break;
522+
default:
523+
writel_relaxed(value, addr);
524+
break;
525+
}
526+
527+
/*
528+
* Monitor changes to PCI_PRIMARY_BUS register on Root Port
529+
* and update local copy of root bus number accordingly.
530+
*/
531+
if (busno == pcie->root_bus_nr && where == PCI_PRIMARY_BUS)
532+
pcie->root_bus_nr = value & 0xff;
533+
534+
return PCIBIOS_SUCCESSFUL;
535+
}
536+
537+
static int aglx_ep_write_cfg(struct altera_pcie *pcie, u8 busno,
538+
unsigned int devfn, int where, int size, u32 value)
539+
{
540+
cra_writel(pcie, ((busno << 8) | devfn), AGLX_BDF_REG);
541+
if (busno > AGLX_RP_SECONDARY(pcie))
542+
where |= FIELD_PREP(AGLX_CFG_TARGET, AGLX_CFG_TARGET_TYPE1);
543+
544+
switch (size) {
545+
case 1:
546+
cra_writeb(pcie, value, where);
547+
break;
548+
case 2:
549+
cra_writew(pcie, value, where);
550+
break;
551+
default:
552+
cra_writel(pcie, value, where);
553+
break;
554+
}
555+
556+
return PCIBIOS_SUCCESSFUL;
557+
}
558+
559+
static int aglx_ep_read_cfg(struct altera_pcie *pcie, u8 busno,
560+
unsigned int devfn, int where, int size, u32 *value)
561+
{
562+
cra_writel(pcie, ((busno << 8) | devfn), AGLX_BDF_REG);
563+
if (busno > AGLX_RP_SECONDARY(pcie))
564+
where |= FIELD_PREP(AGLX_CFG_TARGET, AGLX_CFG_TARGET_TYPE1);
565+
566+
switch (size) {
567+
case 1:
568+
*value = cra_readb(pcie, where);
569+
break;
570+
case 2:
571+
*value = cra_readw(pcie, where);
572+
break;
573+
default:
574+
*value = cra_readl(pcie, where);
575+
break;
576+
}
577+
578+
return PCIBIOS_SUCCESSFUL;
579+
}
580+
428581
static int _altera_pcie_cfg_read(struct altera_pcie *pcie, u8 busno,
429582
unsigned int devfn, int where, int size,
430583
u32 *value)
@@ -437,6 +590,10 @@ static int _altera_pcie_cfg_read(struct altera_pcie *pcie, u8 busno,
437590
return pcie->pcie_data->ops->rp_read_cfg(pcie, where,
438591
size, value);
439592

593+
if (pcie->pcie_data->ops->ep_read_cfg)
594+
return pcie->pcie_data->ops->ep_read_cfg(pcie, busno, devfn,
595+
where, size, value);
596+
440597
switch (size) {
441598
case 1:
442599
byte_en = 1 << (where & 3);
@@ -481,6 +638,10 @@ static int _altera_pcie_cfg_write(struct altera_pcie *pcie, u8 busno,
481638
return pcie->pcie_data->ops->rp_write_cfg(pcie, busno,
482639
where, size, value);
483640

641+
if (pcie->pcie_data->ops->ep_write_cfg)
642+
return pcie->pcie_data->ops->ep_write_cfg(pcie, busno, devfn,
643+
where, size, value);
644+
484645
switch (size) {
485646
case 1:
486647
data32 = (value & 0xff) << shift;
@@ -659,7 +820,32 @@ static void altera_pcie_isr(struct irq_desc *desc)
659820
dev_err_ratelimited(dev, "unexpected IRQ, INT%d\n", bit);
660821
}
661822
}
823+
chained_irq_exit(chip, desc);
824+
}
825+
826+
static void aglx_isr(struct irq_desc *desc)
827+
{
828+
struct irq_chip *chip = irq_desc_get_chip(desc);
829+
struct altera_pcie *pcie;
830+
struct device *dev;
831+
u32 status;
832+
int ret;
833+
834+
chained_irq_enter(chip, desc);
835+
pcie = irq_desc_get_handler_data(desc);
836+
dev = &pcie->pdev->dev;
837+
838+
status = readl(pcie->hip_base + pcie->pcie_data->port_conf_offset +
839+
pcie->pcie_data->port_irq_status_offset);
662840

841+
if (status & CFG_AER) {
842+
writel(CFG_AER, (pcie->hip_base + pcie->pcie_data->port_conf_offset +
843+
pcie->pcie_data->port_irq_status_offset));
844+
845+
ret = generic_handle_domain_irq(pcie->irq_domain, 0);
846+
if (ret)
847+
dev_err_ratelimited(dev, "unexpected IRQ %d\n", pcie->irq);
848+
}
663849
chained_irq_exit(chip, desc);
664850
}
665851

@@ -694,9 +880,9 @@ static int altera_pcie_parse_dt(struct altera_pcie *pcie)
694880
if (IS_ERR(pcie->cra_base))
695881
return PTR_ERR(pcie->cra_base);
696882

697-
if (pcie->pcie_data->version == ALTERA_PCIE_V2) {
698-
pcie->hip_base =
699-
devm_platform_ioremap_resource_byname(pdev, "Hip");
883+
if (pcie->pcie_data->version == ALTERA_PCIE_V2 ||
884+
pcie->pcie_data->version == ALTERA_PCIE_V3) {
885+
pcie->hip_base = devm_platform_ioremap_resource_byname(pdev, "Hip");
700886
if (IS_ERR(pcie->hip_base))
701887
return PTR_ERR(pcie->hip_base);
702888
}
@@ -706,7 +892,7 @@ static int altera_pcie_parse_dt(struct altera_pcie *pcie)
706892
if (pcie->irq < 0)
707893
return pcie->irq;
708894

709-
irq_set_chained_handler_and_data(pcie->irq, altera_pcie_isr, pcie);
895+
irq_set_chained_handler_and_data(pcie->irq, pcie->pcie_data->ops->rp_isr, pcie);
710896
return 0;
711897
}
712898

@@ -719,6 +905,7 @@ static const struct altera_pcie_ops altera_pcie_ops_1_0 = {
719905
.tlp_read_pkt = tlp_read_packet,
720906
.tlp_write_pkt = tlp_write_packet,
721907
.get_link_status = altera_pcie_link_up,
908+
.rp_isr = altera_pcie_isr,
722909
};
723910

724911
static const struct altera_pcie_ops altera_pcie_ops_2_0 = {
@@ -727,6 +914,16 @@ static const struct altera_pcie_ops altera_pcie_ops_2_0 = {
727914
.get_link_status = s10_altera_pcie_link_up,
728915
.rp_read_cfg = s10_rp_read_cfg,
729916
.rp_write_cfg = s10_rp_write_cfg,
917+
.rp_isr = altera_pcie_isr,
918+
};
919+
920+
static const struct altera_pcie_ops altera_pcie_ops_3_0 = {
921+
.rp_read_cfg = aglx_rp_read_cfg,
922+
.rp_write_cfg = aglx_rp_write_cfg,
923+
.get_link_status = aglx_altera_pcie_link_up,
924+
.ep_read_cfg = aglx_ep_read_cfg,
925+
.ep_write_cfg = aglx_ep_write_cfg,
926+
.rp_isr = aglx_isr,
730927
};
731928

732929
static const struct altera_pcie_data altera_pcie_1_0_data = {
@@ -749,11 +946,44 @@ static const struct altera_pcie_data altera_pcie_2_0_data = {
749946
.cfgwr1 = S10_TLP_FMTTYPE_CFGWR1,
750947
};
751948

949+
static const struct altera_pcie_data altera_pcie_3_0_f_tile_data = {
950+
.ops = &altera_pcie_ops_3_0,
951+
.version = ALTERA_PCIE_V3,
952+
.cap_offset = 0x70,
953+
.port_conf_offset = 0x14000,
954+
.port_irq_status_offset = AGLX_ROOT_PORT_IRQ_STATUS,
955+
.port_irq_enable_offset = AGLX_ROOT_PORT_IRQ_ENABLE,
956+
};
957+
958+
static const struct altera_pcie_data altera_pcie_3_0_p_tile_data = {
959+
.ops = &altera_pcie_ops_3_0,
960+
.version = ALTERA_PCIE_V3,
961+
.cap_offset = 0x70,
962+
.port_conf_offset = 0x104000,
963+
.port_irq_status_offset = AGLX_ROOT_PORT_IRQ_STATUS,
964+
.port_irq_enable_offset = AGLX_ROOT_PORT_IRQ_ENABLE,
965+
};
966+
967+
static const struct altera_pcie_data altera_pcie_3_0_r_tile_data = {
968+
.ops = &altera_pcie_ops_3_0,
969+
.version = ALTERA_PCIE_V3,
970+
.cap_offset = 0x70,
971+
.port_conf_offset = 0x1300,
972+
.port_irq_status_offset = 0x0,
973+
.port_irq_enable_offset = 0x4,
974+
};
975+
752976
static const struct of_device_id altera_pcie_of_match[] = {
753977
{.compatible = "altr,pcie-root-port-1.0",
754978
.data = &altera_pcie_1_0_data },
755979
{.compatible = "altr,pcie-root-port-2.0",
756980
.data = &altera_pcie_2_0_data },
981+
{.compatible = "altr,pcie-root-port-3.0-f-tile",
982+
.data = &altera_pcie_3_0_f_tile_data },
983+
{.compatible = "altr,pcie-root-port-3.0-p-tile",
984+
.data = &altera_pcie_3_0_p_tile_data },
985+
{.compatible = "altr,pcie-root-port-3.0-r-tile",
986+
.data = &altera_pcie_3_0_r_tile_data },
757987
{},
758988
};
759989

@@ -791,11 +1021,18 @@ static int altera_pcie_probe(struct platform_device *pdev)
7911021
return ret;
7921022
}
7931023

794-
/* clear all interrupts */
795-
cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS);
796-
/* enable all interrupts */
797-
cra_writel(pcie, P2A_INT_ENA_ALL, P2A_INT_ENABLE);
798-
altera_pcie_host_init(pcie);
1024+
if (pcie->pcie_data->version == ALTERA_PCIE_V1 ||
1025+
pcie->pcie_data->version == ALTERA_PCIE_V2) {
1026+
/* clear all interrupts */
1027+
cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS);
1028+
/* enable all interrupts */
1029+
cra_writel(pcie, P2A_INT_ENA_ALL, P2A_INT_ENABLE);
1030+
altera_pcie_host_init(pcie);
1031+
} else if (pcie->pcie_data->version == ALTERA_PCIE_V3) {
1032+
writel(CFG_AER,
1033+
pcie->hip_base + pcie->pcie_data->port_conf_offset +
1034+
pcie->pcie_data->port_irq_enable_offset);
1035+
}
7991036

8001037
bridge->sysdata = pcie;
8011038
bridge->busnr = pcie->root_bus_nr;

0 commit comments

Comments
 (0)