1*9aa0cb68SJacky Chou // SPDX-License-Identifier: GPL-2.0+ 2*9aa0cb68SJacky Chou /* 3*9aa0cb68SJacky Chou * Copyright 2025 Aspeed Technology Inc. 4*9aa0cb68SJacky Chou */ 5*9aa0cb68SJacky Chou #include <linux/bitfield.h> 6*9aa0cb68SJacky Chou #include <linux/clk.h> 7*9aa0cb68SJacky Chou #include <linux/interrupt.h> 8*9aa0cb68SJacky Chou #include <linux/irq.h> 9*9aa0cb68SJacky Chou #include <linux/irqdomain.h> 10*9aa0cb68SJacky Chou #include <linux/irqchip/chained_irq.h> 11*9aa0cb68SJacky Chou #include <linux/irqchip/irq-msi-lib.h> 12*9aa0cb68SJacky Chou #include <linux/kernel.h> 13*9aa0cb68SJacky Chou #include <linux/mfd/syscon.h> 14*9aa0cb68SJacky Chou #include <linux/module.h> 15*9aa0cb68SJacky Chou #include <linux/msi.h> 16*9aa0cb68SJacky Chou #include <linux/mutex.h> 17*9aa0cb68SJacky Chou #include <linux/of.h> 18*9aa0cb68SJacky Chou #include <linux/of_address.h> 19*9aa0cb68SJacky Chou #include <linux/of_pci.h> 20*9aa0cb68SJacky Chou #include <linux/pci.h> 21*9aa0cb68SJacky Chou #include <linux/platform_device.h> 22*9aa0cb68SJacky Chou #include <linux/phy/pcie.h> 23*9aa0cb68SJacky Chou #include <linux/phy/phy.h> 24*9aa0cb68SJacky Chou #include <linux/regmap.h> 25*9aa0cb68SJacky Chou #include <linux/reset.h> 26*9aa0cb68SJacky Chou 27*9aa0cb68SJacky Chou #include "../pci.h" 28*9aa0cb68SJacky Chou 29*9aa0cb68SJacky Chou #define MAX_MSI_HOST_IRQS 64 30*9aa0cb68SJacky Chou #define ASPEED_RESET_RC_WAIT_MS 10 31*9aa0cb68SJacky Chou 32*9aa0cb68SJacky Chou /* AST2600 AHBC Registers */ 33*9aa0cb68SJacky Chou #define ASPEED_AHBC_KEY 0x00 34*9aa0cb68SJacky Chou #define ASPEED_AHBC_UNLOCK_KEY 0xaeed1a03 35*9aa0cb68SJacky Chou #define ASPEED_AHBC_UNLOCK 0x01 36*9aa0cb68SJacky Chou #define ASPEED_AHBC_ADDR_MAPPING 0x8c 37*9aa0cb68SJacky Chou #define ASPEED_PCIE_RC_MEMORY_EN BIT(5) 38*9aa0cb68SJacky Chou 39*9aa0cb68SJacky Chou /* AST2600 H2X Controller Registers */ 40*9aa0cb68SJacky Chou #define ASPEED_H2X_INT_STS 0x08 41*9aa0cb68SJacky Chou #define ASPEED_PCIE_TX_IDLE_CLEAR BIT(0) 42*9aa0cb68SJacky Chou #define ASPEED_PCIE_INTX_STS GENMASK(3, 0) 43*9aa0cb68SJacky Chou #define ASPEED_H2X_HOST_RX_DESC_DATA 0x0c 44*9aa0cb68SJacky Chou #define ASPEED_H2X_TX_DESC0 0x10 45*9aa0cb68SJacky Chou #define ASPEED_H2X_TX_DESC1 0x14 46*9aa0cb68SJacky Chou #define ASPEED_H2X_TX_DESC2 0x18 47*9aa0cb68SJacky Chou #define ASPEED_H2X_TX_DESC3 0x1c 48*9aa0cb68SJacky Chou #define ASPEED_H2X_TX_DESC_DATA 0x20 49*9aa0cb68SJacky Chou #define ASPEED_H2X_STS 0x24 50*9aa0cb68SJacky Chou #define ASPEED_PCIE_TX_IDLE BIT(31) 51*9aa0cb68SJacky Chou #define ASPEED_PCIE_STATUS_OF_TX GENMASK(25, 24) 52*9aa0cb68SJacky Chou #define ASPEED_PCIE_RC_H_TX_COMPLETE BIT(25) 53*9aa0cb68SJacky Chou #define ASPEED_PCIE_TRIGGER_TX BIT(0) 54*9aa0cb68SJacky Chou #define ASPEED_H2X_AHB_ADDR_CONFIG0 0x60 55*9aa0cb68SJacky Chou #define ASPEED_AHB_REMAP_LO_ADDR(x) (x & GENMASK(15, 4)) 56*9aa0cb68SJacky Chou #define ASPEED_AHB_MASK_LO_ADDR(x) FIELD_PREP(GENMASK(31, 20), x) 57*9aa0cb68SJacky Chou #define ASPEED_H2X_AHB_ADDR_CONFIG1 0x64 58*9aa0cb68SJacky Chou #define ASPEED_AHB_REMAP_HI_ADDR(x) (x) 59*9aa0cb68SJacky Chou #define ASPEED_H2X_AHB_ADDR_CONFIG2 0x68 60*9aa0cb68SJacky Chou #define ASPEED_AHB_MASK_HI_ADDR(x) (x) 61*9aa0cb68SJacky Chou #define ASPEED_H2X_DEV_CTRL 0xc0 62*9aa0cb68SJacky Chou #define ASPEED_PCIE_RX_DMA_EN BIT(9) 63*9aa0cb68SJacky Chou #define ASPEED_PCIE_RX_LINEAR BIT(8) 64*9aa0cb68SJacky Chou #define ASPEED_PCIE_RX_MSI_SEL BIT(7) 65*9aa0cb68SJacky Chou #define ASPEED_PCIE_RX_MSI_EN BIT(6) 66*9aa0cb68SJacky Chou #define ASPEED_PCIE_UNLOCK_RX_BUFF BIT(4) 67*9aa0cb68SJacky Chou #define ASPEED_PCIE_WAIT_RX_TLP_CLR BIT(2) 68*9aa0cb68SJacky Chou #define ASPEED_PCIE_RC_RX_ENABLE BIT(1) 69*9aa0cb68SJacky Chou #define ASPEED_PCIE_RC_ENABLE BIT(0) 70*9aa0cb68SJacky Chou #define ASPEED_H2X_DEV_STS 0xc8 71*9aa0cb68SJacky Chou #define ASPEED_PCIE_RC_RX_DONE_ISR BIT(4) 72*9aa0cb68SJacky Chou #define ASPEED_H2X_DEV_RX_DESC_DATA 0xcc 73*9aa0cb68SJacky Chou #define ASPEED_H2X_DEV_RX_DESC1 0xd4 74*9aa0cb68SJacky Chou #define ASPEED_H2X_DEV_TX_TAG 0xfc 75*9aa0cb68SJacky Chou #define ASPEED_RC_TLP_TX_TAG_NUM 0x28 76*9aa0cb68SJacky Chou 77*9aa0cb68SJacky Chou /* AST2700 H2X */ 78*9aa0cb68SJacky Chou #define ASPEED_H2X_CTRL 0x00 79*9aa0cb68SJacky Chou #define ASPEED_H2X_BRIDGE_EN BIT(0) 80*9aa0cb68SJacky Chou #define ASPEED_H2X_BRIDGE_DIRECT_EN BIT(1) 81*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGE_INT_STS 0x08 82*9aa0cb68SJacky Chou #define ASPEED_CFGE_TX_IDLE BIT(0) 83*9aa0cb68SJacky Chou #define ASPEED_CFGE_RX_BUSY BIT(1) 84*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGI_TLP 0x20 85*9aa0cb68SJacky Chou #define ASPEED_CFGI_BYTE_EN_MASK GENMASK(19, 16) 86*9aa0cb68SJacky Chou #define ASPEED_CFGI_BYTE_EN(x) \ 87*9aa0cb68SJacky Chou FIELD_PREP(ASPEED_CFGI_BYTE_EN_MASK, (x)) 88*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGI_WR_DATA 0x24 89*9aa0cb68SJacky Chou #define ASPEED_CFGI_WRITE BIT(20) 90*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGI_CTRL 0x28 91*9aa0cb68SJacky Chou #define ASPEED_CFGI_TLP_FIRE BIT(0) 92*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGI_RET_DATA 0x2c 93*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGE_TLP_1ST 0x30 94*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGE_TLP_NEXT 0x34 95*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGE_CTRL 0x38 96*9aa0cb68SJacky Chou #define ASPEED_CFGE_TLP_FIRE BIT(0) 97*9aa0cb68SJacky Chou #define ASPEED_H2X_CFGE_RET_DATA 0x3c 98*9aa0cb68SJacky Chou #define ASPEED_H2X_REMAP_PREF_ADDR 0x70 99*9aa0cb68SJacky Chou #define ASPEED_REMAP_PREF_ADDR_63_32(x) (x) 100*9aa0cb68SJacky Chou #define ASPEED_H2X_REMAP_PCI_ADDR_HI 0x74 101*9aa0cb68SJacky Chou #define ASPEED_REMAP_PCI_ADDR_63_32(x) (((x) >> 32) & GENMASK(31, 0)) 102*9aa0cb68SJacky Chou #define ASPEED_H2X_REMAP_PCI_ADDR_LO 0x78 103*9aa0cb68SJacky Chou #define ASPEED_REMAP_PCI_ADDR_31_12(x) ((x) & GENMASK(31, 12)) 104*9aa0cb68SJacky Chou 105*9aa0cb68SJacky Chou /* AST2700 SCU */ 106*9aa0cb68SJacky Chou #define ASPEED_SCU_60 0x60 107*9aa0cb68SJacky Chou #define ASPEED_RC_E2M_PATH_EN BIT(0) 108*9aa0cb68SJacky Chou #define ASPEED_RC_H2XS_PATH_EN BIT(16) 109*9aa0cb68SJacky Chou #define ASPEED_RC_H2XD_PATH_EN BIT(17) 110*9aa0cb68SJacky Chou #define ASPEED_RC_H2XX_PATH_EN BIT(18) 111*9aa0cb68SJacky Chou #define ASPEED_RC_UPSTREAM_MEM_EN BIT(19) 112*9aa0cb68SJacky Chou #define ASPEED_SCU_64 0x64 113*9aa0cb68SJacky Chou #define ASPEED_RC0_DECODE_DMA_BASE(x) FIELD_PREP(GENMASK(7, 0), x) 114*9aa0cb68SJacky Chou #define ASPEED_RC0_DECODE_DMA_LIMIT(x) FIELD_PREP(GENMASK(15, 8), x) 115*9aa0cb68SJacky Chou #define ASPEED_RC1_DECODE_DMA_BASE(x) FIELD_PREP(GENMASK(23, 16), x) 116*9aa0cb68SJacky Chou #define ASPEED_RC1_DECODE_DMA_LIMIT(x) FIELD_PREP(GENMASK(31, 24), x) 117*9aa0cb68SJacky Chou #define ASPEED_SCU_70 0x70 118*9aa0cb68SJacky Chou #define ASPEED_DISABLE_EP_FUNC 0 119*9aa0cb68SJacky Chou 120*9aa0cb68SJacky Chou /* Macro to combine Fmt and Type into the 8-bit field */ 121*9aa0cb68SJacky Chou #define ASPEED_TLP_FMT_TYPE(fmt, type) ((((fmt) & 0x7) << 5) | ((type) & 0x1f)) 122*9aa0cb68SJacky Chou #define ASPEED_TLP_COMMON_FIELDS GENMASK(31, 24) 123*9aa0cb68SJacky Chou 124*9aa0cb68SJacky Chou /* Completion status */ 125*9aa0cb68SJacky Chou #define CPL_STS(x) FIELD_GET(GENMASK(15, 13), (x)) 126*9aa0cb68SJacky Chou /* TLP configuration type 0 and type 1 */ 127*9aa0cb68SJacky Chou #define CFG0_READ_FMTTYPE \ 128*9aa0cb68SJacky Chou FIELD_PREP(ASPEED_TLP_COMMON_FIELDS, \ 129*9aa0cb68SJacky Chou ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_NO_DATA, \ 130*9aa0cb68SJacky Chou PCIE_TLP_TYPE_CFG0_RD)) 131*9aa0cb68SJacky Chou #define CFG0_WRITE_FMTTYPE \ 132*9aa0cb68SJacky Chou FIELD_PREP(ASPEED_TLP_COMMON_FIELDS, \ 133*9aa0cb68SJacky Chou ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_DATA, \ 134*9aa0cb68SJacky Chou PCIE_TLP_TYPE_CFG0_WR)) 135*9aa0cb68SJacky Chou #define CFG1_READ_FMTTYPE \ 136*9aa0cb68SJacky Chou FIELD_PREP(ASPEED_TLP_COMMON_FIELDS, \ 137*9aa0cb68SJacky Chou ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_NO_DATA, \ 138*9aa0cb68SJacky Chou PCIE_TLP_TYPE_CFG1_RD)) 139*9aa0cb68SJacky Chou #define CFG1_WRITE_FMTTYPE \ 140*9aa0cb68SJacky Chou FIELD_PREP(ASPEED_TLP_COMMON_FIELDS, \ 141*9aa0cb68SJacky Chou ASPEED_TLP_FMT_TYPE(PCIE_TLP_FMT_3DW_DATA, \ 142*9aa0cb68SJacky Chou PCIE_TLP_TYPE_CFG1_WR)) 143*9aa0cb68SJacky Chou #define CFG_PAYLOAD_SIZE 0x01 /* 1 DWORD */ 144*9aa0cb68SJacky Chou #define TLP_HEADER_BYTE_EN(x, y) ((GENMASK((x) - 1, 0) << ((y) % 4))) 145*9aa0cb68SJacky Chou #define TLP_GET_VALUE(x, y, z) \ 146*9aa0cb68SJacky Chou (((x) >> ((((z) % 4)) * 8)) & GENMASK((8 * (y)) - 1, 0)) 147*9aa0cb68SJacky Chou #define TLP_SET_VALUE(x, y, z) \ 148*9aa0cb68SJacky Chou ((((x) & GENMASK((8 * (y)) - 1, 0)) << ((((z) % 4)) * 8))) 149*9aa0cb68SJacky Chou #define AST2600_TX_DESC1_VALUE 0x00002000 150*9aa0cb68SJacky Chou #define AST2700_TX_DESC1_VALUE 0x00401000 151*9aa0cb68SJacky Chou 152*9aa0cb68SJacky Chou /** 153*9aa0cb68SJacky Chou * struct aspeed_pcie_port - PCIe port information 154*9aa0cb68SJacky Chou * @list: port list 155*9aa0cb68SJacky Chou * @pcie: pointer to PCIe host info 156*9aa0cb68SJacky Chou * @clk: pointer to the port clock gate 157*9aa0cb68SJacky Chou * @phy: pointer to PCIe PHY 158*9aa0cb68SJacky Chou * @perst: pointer to port reset control 159*9aa0cb68SJacky Chou * @slot: port slot 160*9aa0cb68SJacky Chou */ 161*9aa0cb68SJacky Chou struct aspeed_pcie_port { 162*9aa0cb68SJacky Chou struct list_head list; 163*9aa0cb68SJacky Chou struct aspeed_pcie *pcie; 164*9aa0cb68SJacky Chou struct clk *clk; 165*9aa0cb68SJacky Chou struct phy *phy; 166*9aa0cb68SJacky Chou struct reset_control *perst; 167*9aa0cb68SJacky Chou u32 slot; 168*9aa0cb68SJacky Chou }; 169*9aa0cb68SJacky Chou 170*9aa0cb68SJacky Chou /** 171*9aa0cb68SJacky Chou * struct aspeed_pcie - PCIe RC information 172*9aa0cb68SJacky Chou * @host: pointer to PCIe host bridge 173*9aa0cb68SJacky Chou * @dev: pointer to device structure 174*9aa0cb68SJacky Chou * @reg: PCIe host register base address 175*9aa0cb68SJacky Chou * @ahbc: pointer to AHHC register map 176*9aa0cb68SJacky Chou * @cfg: pointer to Aspeed PCIe configuration register map 177*9aa0cb68SJacky Chou * @platform: platform specific information 178*9aa0cb68SJacky Chou * @ports: list of PCIe ports 179*9aa0cb68SJacky Chou * @tx_tag: current TX tag for the port 180*9aa0cb68SJacky Chou * @root_bus_nr: bus number of the host bridge 181*9aa0cb68SJacky Chou * @h2xrst: pointer to H2X reset control 182*9aa0cb68SJacky Chou * @intx_domain: IRQ domain for INTx interrupts 183*9aa0cb68SJacky Chou * @msi_domain: IRQ domain for MSI interrupts 184*9aa0cb68SJacky Chou * @lock: mutex to protect MSI bitmap variable 185*9aa0cb68SJacky Chou * @msi_irq_in_use: bitmap to track used MSI host IRQs 186*9aa0cb68SJacky Chou * @clear_msi_twice: AST2700 workaround to clear MSI status twice 187*9aa0cb68SJacky Chou */ 188*9aa0cb68SJacky Chou struct aspeed_pcie { 189*9aa0cb68SJacky Chou struct pci_host_bridge *host; 190*9aa0cb68SJacky Chou struct device *dev; 191*9aa0cb68SJacky Chou void __iomem *reg; 192*9aa0cb68SJacky Chou struct regmap *ahbc; 193*9aa0cb68SJacky Chou struct regmap *cfg; 194*9aa0cb68SJacky Chou const struct aspeed_pcie_rc_platform *platform; 195*9aa0cb68SJacky Chou struct list_head ports; 196*9aa0cb68SJacky Chou 197*9aa0cb68SJacky Chou u8 tx_tag; 198*9aa0cb68SJacky Chou u8 root_bus_nr; 199*9aa0cb68SJacky Chou 200*9aa0cb68SJacky Chou struct reset_control *h2xrst; 201*9aa0cb68SJacky Chou 202*9aa0cb68SJacky Chou struct irq_domain *intx_domain; 203*9aa0cb68SJacky Chou struct irq_domain *msi_domain; 204*9aa0cb68SJacky Chou struct mutex lock; 205*9aa0cb68SJacky Chou DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_HOST_IRQS); 206*9aa0cb68SJacky Chou 207*9aa0cb68SJacky Chou bool clear_msi_twice; /* AST2700 workaround */ 208*9aa0cb68SJacky Chou }; 209*9aa0cb68SJacky Chou 210*9aa0cb68SJacky Chou /** 211*9aa0cb68SJacky Chou * struct aspeed_pcie_rc_platform - Platform information 212*9aa0cb68SJacky Chou * @setup: initialization function 213*9aa0cb68SJacky Chou * @pcie_map_ranges: function to map PCIe address ranges 214*9aa0cb68SJacky Chou * @reg_intx_en: INTx enable register offset 215*9aa0cb68SJacky Chou * @reg_intx_sts: INTx status register offset 216*9aa0cb68SJacky Chou * @reg_msi_en: MSI enable register offset 217*9aa0cb68SJacky Chou * @reg_msi_sts: MSI enable register offset 218*9aa0cb68SJacky Chou * @msi_address: HW fixed MSI address 219*9aa0cb68SJacky Chou */ 220*9aa0cb68SJacky Chou struct aspeed_pcie_rc_platform { 221*9aa0cb68SJacky Chou int (*setup)(struct platform_device *pdev); 222*9aa0cb68SJacky Chou void (*pcie_map_ranges)(struct aspeed_pcie *pcie, u64 pci_addr); 223*9aa0cb68SJacky Chou int reg_intx_en; 224*9aa0cb68SJacky Chou int reg_intx_sts; 225*9aa0cb68SJacky Chou int reg_msi_en; 226*9aa0cb68SJacky Chou int reg_msi_sts; 227*9aa0cb68SJacky Chou u32 msi_address; 228*9aa0cb68SJacky Chou }; 229*9aa0cb68SJacky Chou 230*9aa0cb68SJacky Chou static void aspeed_pcie_intx_irq_ack(struct irq_data *d) 231*9aa0cb68SJacky Chou { 232*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d); 233*9aa0cb68SJacky Chou int intx_en = pcie->platform->reg_intx_en; 234*9aa0cb68SJacky Chou u32 en; 235*9aa0cb68SJacky Chou 236*9aa0cb68SJacky Chou en = readl(pcie->reg + intx_en); 237*9aa0cb68SJacky Chou en |= BIT(d->hwirq); 238*9aa0cb68SJacky Chou writel(en, pcie->reg + intx_en); 239*9aa0cb68SJacky Chou } 240*9aa0cb68SJacky Chou 241*9aa0cb68SJacky Chou static void aspeed_pcie_intx_irq_mask(struct irq_data *d) 242*9aa0cb68SJacky Chou { 243*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d); 244*9aa0cb68SJacky Chou int intx_en = pcie->platform->reg_intx_en; 245*9aa0cb68SJacky Chou u32 en; 246*9aa0cb68SJacky Chou 247*9aa0cb68SJacky Chou en = readl(pcie->reg + intx_en); 248*9aa0cb68SJacky Chou en &= ~BIT(d->hwirq); 249*9aa0cb68SJacky Chou writel(en, pcie->reg + intx_en); 250*9aa0cb68SJacky Chou } 251*9aa0cb68SJacky Chou 252*9aa0cb68SJacky Chou static void aspeed_pcie_intx_irq_unmask(struct irq_data *d) 253*9aa0cb68SJacky Chou { 254*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(d); 255*9aa0cb68SJacky Chou int intx_en = pcie->platform->reg_intx_en; 256*9aa0cb68SJacky Chou u32 en; 257*9aa0cb68SJacky Chou 258*9aa0cb68SJacky Chou en = readl(pcie->reg + intx_en); 259*9aa0cb68SJacky Chou en |= BIT(d->hwirq); 260*9aa0cb68SJacky Chou writel(en, pcie->reg + intx_en); 261*9aa0cb68SJacky Chou } 262*9aa0cb68SJacky Chou 263*9aa0cb68SJacky Chou static struct irq_chip aspeed_intx_irq_chip = { 264*9aa0cb68SJacky Chou .name = "INTx", 265*9aa0cb68SJacky Chou .irq_ack = aspeed_pcie_intx_irq_ack, 266*9aa0cb68SJacky Chou .irq_mask = aspeed_pcie_intx_irq_mask, 267*9aa0cb68SJacky Chou .irq_unmask = aspeed_pcie_intx_irq_unmask, 268*9aa0cb68SJacky Chou }; 269*9aa0cb68SJacky Chou 270*9aa0cb68SJacky Chou static int aspeed_pcie_intx_map(struct irq_domain *domain, unsigned int irq, 271*9aa0cb68SJacky Chou irq_hw_number_t hwirq) 272*9aa0cb68SJacky Chou { 273*9aa0cb68SJacky Chou irq_set_chip_and_handler(irq, &aspeed_intx_irq_chip, handle_level_irq); 274*9aa0cb68SJacky Chou irq_set_chip_data(irq, domain->host_data); 275*9aa0cb68SJacky Chou irq_set_status_flags(irq, IRQ_LEVEL); 276*9aa0cb68SJacky Chou 277*9aa0cb68SJacky Chou return 0; 278*9aa0cb68SJacky Chou } 279*9aa0cb68SJacky Chou 280*9aa0cb68SJacky Chou static const struct irq_domain_ops aspeed_intx_domain_ops = { 281*9aa0cb68SJacky Chou .map = aspeed_pcie_intx_map, 282*9aa0cb68SJacky Chou }; 283*9aa0cb68SJacky Chou 284*9aa0cb68SJacky Chou static irqreturn_t aspeed_pcie_intr_handler(int irq, void *dev_id) 285*9aa0cb68SJacky Chou { 286*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = dev_id; 287*9aa0cb68SJacky Chou const struct aspeed_pcie_rc_platform *platform = pcie->platform; 288*9aa0cb68SJacky Chou unsigned long status; 289*9aa0cb68SJacky Chou unsigned long intx; 290*9aa0cb68SJacky Chou u32 bit; 291*9aa0cb68SJacky Chou int i; 292*9aa0cb68SJacky Chou 293*9aa0cb68SJacky Chou intx = FIELD_GET(ASPEED_PCIE_INTX_STS, 294*9aa0cb68SJacky Chou readl(pcie->reg + platform->reg_intx_sts)); 295*9aa0cb68SJacky Chou for_each_set_bit(bit, &intx, PCI_NUM_INTX) 296*9aa0cb68SJacky Chou generic_handle_domain_irq(pcie->intx_domain, bit); 297*9aa0cb68SJacky Chou 298*9aa0cb68SJacky Chou for (i = 0; i < 2; i++) { 299*9aa0cb68SJacky Chou int msi_sts_reg = platform->reg_msi_sts + (i * 4); 300*9aa0cb68SJacky Chou 301*9aa0cb68SJacky Chou status = readl(pcie->reg + msi_sts_reg); 302*9aa0cb68SJacky Chou writel(status, pcie->reg + msi_sts_reg); 303*9aa0cb68SJacky Chou 304*9aa0cb68SJacky Chou /* 305*9aa0cb68SJacky Chou * AST2700 workaround: 306*9aa0cb68SJacky Chou * The MSI status needs to clear one more time. 307*9aa0cb68SJacky Chou */ 308*9aa0cb68SJacky Chou if (pcie->clear_msi_twice) 309*9aa0cb68SJacky Chou writel(status, pcie->reg + msi_sts_reg); 310*9aa0cb68SJacky Chou 311*9aa0cb68SJacky Chou for_each_set_bit(bit, &status, 32) { 312*9aa0cb68SJacky Chou bit += (i * 32); 313*9aa0cb68SJacky Chou generic_handle_domain_irq(pcie->msi_domain, bit); 314*9aa0cb68SJacky Chou } 315*9aa0cb68SJacky Chou } 316*9aa0cb68SJacky Chou 317*9aa0cb68SJacky Chou return IRQ_HANDLED; 318*9aa0cb68SJacky Chou } 319*9aa0cb68SJacky Chou 320*9aa0cb68SJacky Chou static u32 aspeed_pcie_get_bdf_offset(struct pci_bus *bus, unsigned int devfn, 321*9aa0cb68SJacky Chou int where) 322*9aa0cb68SJacky Chou { 323*9aa0cb68SJacky Chou return ((bus->number) << 24) | (PCI_SLOT(devfn) << 19) | 324*9aa0cb68SJacky Chou (PCI_FUNC(devfn) << 16) | (where & ~3); 325*9aa0cb68SJacky Chou } 326*9aa0cb68SJacky Chou 327*9aa0cb68SJacky Chou static int aspeed_ast2600_conf(struct pci_bus *bus, unsigned int devfn, 328*9aa0cb68SJacky Chou int where, int size, u32 *val, u32 fmt_type, 329*9aa0cb68SJacky Chou bool write) 330*9aa0cb68SJacky Chou { 331*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = bus->sysdata; 332*9aa0cb68SJacky Chou u32 bdf_offset, cfg_val, isr; 333*9aa0cb68SJacky Chou int ret; 334*9aa0cb68SJacky Chou 335*9aa0cb68SJacky Chou bdf_offset = aspeed_pcie_get_bdf_offset(bus, devfn, where); 336*9aa0cb68SJacky Chou 337*9aa0cb68SJacky Chou /* Driver may set unlock RX buffer before triggering next TX config */ 338*9aa0cb68SJacky Chou cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_CTRL); 339*9aa0cb68SJacky Chou writel(ASPEED_PCIE_UNLOCK_RX_BUFF | cfg_val, 340*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_DEV_CTRL); 341*9aa0cb68SJacky Chou 342*9aa0cb68SJacky Chou cfg_val = fmt_type | CFG_PAYLOAD_SIZE; 343*9aa0cb68SJacky Chou writel(cfg_val, pcie->reg + ASPEED_H2X_TX_DESC0); 344*9aa0cb68SJacky Chou 345*9aa0cb68SJacky Chou cfg_val = AST2600_TX_DESC1_VALUE | 346*9aa0cb68SJacky Chou FIELD_PREP(GENMASK(11, 8), pcie->tx_tag) | 347*9aa0cb68SJacky Chou TLP_HEADER_BYTE_EN(size, where); 348*9aa0cb68SJacky Chou writel(cfg_val, pcie->reg + ASPEED_H2X_TX_DESC1); 349*9aa0cb68SJacky Chou 350*9aa0cb68SJacky Chou writel(bdf_offset, pcie->reg + ASPEED_H2X_TX_DESC2); 351*9aa0cb68SJacky Chou writel(0, pcie->reg + ASPEED_H2X_TX_DESC3); 352*9aa0cb68SJacky Chou if (write) 353*9aa0cb68SJacky Chou writel(TLP_SET_VALUE(*val, size, where), 354*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_TX_DESC_DATA); 355*9aa0cb68SJacky Chou 356*9aa0cb68SJacky Chou cfg_val = readl(pcie->reg + ASPEED_H2X_STS); 357*9aa0cb68SJacky Chou cfg_val |= ASPEED_PCIE_TRIGGER_TX; 358*9aa0cb68SJacky Chou writel(cfg_val, pcie->reg + ASPEED_H2X_STS); 359*9aa0cb68SJacky Chou 360*9aa0cb68SJacky Chou ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_STS, cfg_val, 361*9aa0cb68SJacky Chou (cfg_val & ASPEED_PCIE_TX_IDLE), 0, 50); 362*9aa0cb68SJacky Chou if (ret) { 363*9aa0cb68SJacky Chou dev_err(pcie->dev, 364*9aa0cb68SJacky Chou "%02x:%02x.%d CR tx timeout sts: 0x%08x\n", 365*9aa0cb68SJacky Chou bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), cfg_val); 366*9aa0cb68SJacky Chou ret = PCIBIOS_SET_FAILED; 367*9aa0cb68SJacky Chou PCI_SET_ERROR_RESPONSE(val); 368*9aa0cb68SJacky Chou goto out; 369*9aa0cb68SJacky Chou } 370*9aa0cb68SJacky Chou 371*9aa0cb68SJacky Chou cfg_val = readl(pcie->reg + ASPEED_H2X_INT_STS); 372*9aa0cb68SJacky Chou cfg_val |= ASPEED_PCIE_TX_IDLE_CLEAR; 373*9aa0cb68SJacky Chou writel(cfg_val, pcie->reg + ASPEED_H2X_INT_STS); 374*9aa0cb68SJacky Chou 375*9aa0cb68SJacky Chou cfg_val = readl(pcie->reg + ASPEED_H2X_STS); 376*9aa0cb68SJacky Chou switch (cfg_val & ASPEED_PCIE_STATUS_OF_TX) { 377*9aa0cb68SJacky Chou case ASPEED_PCIE_RC_H_TX_COMPLETE: 378*9aa0cb68SJacky Chou ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_DEV_STS, isr, 379*9aa0cb68SJacky Chou (isr & ASPEED_PCIE_RC_RX_DONE_ISR), 0, 380*9aa0cb68SJacky Chou 50); 381*9aa0cb68SJacky Chou if (ret) { 382*9aa0cb68SJacky Chou dev_err(pcie->dev, 383*9aa0cb68SJacky Chou "%02x:%02x.%d CR rx timeout sts: 0x%08x\n", 384*9aa0cb68SJacky Chou bus->number, PCI_SLOT(devfn), 385*9aa0cb68SJacky Chou PCI_FUNC(devfn), isr); 386*9aa0cb68SJacky Chou ret = PCIBIOS_SET_FAILED; 387*9aa0cb68SJacky Chou PCI_SET_ERROR_RESPONSE(val); 388*9aa0cb68SJacky Chou goto out; 389*9aa0cb68SJacky Chou } 390*9aa0cb68SJacky Chou if (!write) { 391*9aa0cb68SJacky Chou cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_RX_DESC1); 392*9aa0cb68SJacky Chou if (CPL_STS(cfg_val) != PCIE_CPL_STS_SUCCESS) { 393*9aa0cb68SJacky Chou ret = PCIBIOS_SET_FAILED; 394*9aa0cb68SJacky Chou PCI_SET_ERROR_RESPONSE(val); 395*9aa0cb68SJacky Chou goto out; 396*9aa0cb68SJacky Chou } else { 397*9aa0cb68SJacky Chou *val = readl(pcie->reg + 398*9aa0cb68SJacky Chou ASPEED_H2X_DEV_RX_DESC_DATA); 399*9aa0cb68SJacky Chou } 400*9aa0cb68SJacky Chou } 401*9aa0cb68SJacky Chou break; 402*9aa0cb68SJacky Chou case ASPEED_PCIE_STATUS_OF_TX: 403*9aa0cb68SJacky Chou ret = PCIBIOS_SET_FAILED; 404*9aa0cb68SJacky Chou PCI_SET_ERROR_RESPONSE(val); 405*9aa0cb68SJacky Chou goto out; 406*9aa0cb68SJacky Chou default: 407*9aa0cb68SJacky Chou *val = readl(pcie->reg + ASPEED_H2X_HOST_RX_DESC_DATA); 408*9aa0cb68SJacky Chou break; 409*9aa0cb68SJacky Chou } 410*9aa0cb68SJacky Chou 411*9aa0cb68SJacky Chou cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_CTRL); 412*9aa0cb68SJacky Chou cfg_val |= ASPEED_PCIE_UNLOCK_RX_BUFF; 413*9aa0cb68SJacky Chou writel(cfg_val, pcie->reg + ASPEED_H2X_DEV_CTRL); 414*9aa0cb68SJacky Chou 415*9aa0cb68SJacky Chou *val = TLP_GET_VALUE(*val, size, where); 416*9aa0cb68SJacky Chou 417*9aa0cb68SJacky Chou ret = PCIBIOS_SUCCESSFUL; 418*9aa0cb68SJacky Chou out: 419*9aa0cb68SJacky Chou cfg_val = readl(pcie->reg + ASPEED_H2X_DEV_STS); 420*9aa0cb68SJacky Chou writel(cfg_val, pcie->reg + ASPEED_H2X_DEV_STS); 421*9aa0cb68SJacky Chou pcie->tx_tag = (pcie->tx_tag + 1) % 0x8; 422*9aa0cb68SJacky Chou return ret; 423*9aa0cb68SJacky Chou } 424*9aa0cb68SJacky Chou 425*9aa0cb68SJacky Chou static int aspeed_ast2600_rd_conf(struct pci_bus *bus, unsigned int devfn, 426*9aa0cb68SJacky Chou int where, int size, u32 *val) 427*9aa0cb68SJacky Chou { 428*9aa0cb68SJacky Chou /* 429*9aa0cb68SJacky Chou * AST2600 has only one Root Port on the root bus. 430*9aa0cb68SJacky Chou */ 431*9aa0cb68SJacky Chou if (PCI_SLOT(devfn) != 8) 432*9aa0cb68SJacky Chou return PCIBIOS_DEVICE_NOT_FOUND; 433*9aa0cb68SJacky Chou 434*9aa0cb68SJacky Chou return aspeed_ast2600_conf(bus, devfn, where, size, val, 435*9aa0cb68SJacky Chou CFG0_READ_FMTTYPE, false); 436*9aa0cb68SJacky Chou } 437*9aa0cb68SJacky Chou 438*9aa0cb68SJacky Chou static int aspeed_ast2600_child_rd_conf(struct pci_bus *bus, unsigned int devfn, 439*9aa0cb68SJacky Chou int where, int size, u32 *val) 440*9aa0cb68SJacky Chou { 441*9aa0cb68SJacky Chou return aspeed_ast2600_conf(bus, devfn, where, size, val, 442*9aa0cb68SJacky Chou CFG1_READ_FMTTYPE, false); 443*9aa0cb68SJacky Chou } 444*9aa0cb68SJacky Chou 445*9aa0cb68SJacky Chou static int aspeed_ast2600_wr_conf(struct pci_bus *bus, unsigned int devfn, 446*9aa0cb68SJacky Chou int where, int size, u32 val) 447*9aa0cb68SJacky Chou { 448*9aa0cb68SJacky Chou /* 449*9aa0cb68SJacky Chou * AST2600 has only one Root Port on the root bus. 450*9aa0cb68SJacky Chou */ 451*9aa0cb68SJacky Chou if (PCI_SLOT(devfn) != 8) 452*9aa0cb68SJacky Chou return PCIBIOS_DEVICE_NOT_FOUND; 453*9aa0cb68SJacky Chou 454*9aa0cb68SJacky Chou return aspeed_ast2600_conf(bus, devfn, where, size, &val, 455*9aa0cb68SJacky Chou CFG0_WRITE_FMTTYPE, true); 456*9aa0cb68SJacky Chou } 457*9aa0cb68SJacky Chou 458*9aa0cb68SJacky Chou static int aspeed_ast2600_child_wr_conf(struct pci_bus *bus, unsigned int devfn, 459*9aa0cb68SJacky Chou int where, int size, u32 val) 460*9aa0cb68SJacky Chou { 461*9aa0cb68SJacky Chou return aspeed_ast2600_conf(bus, devfn, where, size, &val, 462*9aa0cb68SJacky Chou CFG1_WRITE_FMTTYPE, true); 463*9aa0cb68SJacky Chou } 464*9aa0cb68SJacky Chou 465*9aa0cb68SJacky Chou static int aspeed_ast2700_config(struct pci_bus *bus, unsigned int devfn, 466*9aa0cb68SJacky Chou int where, int size, u32 *val, bool write) 467*9aa0cb68SJacky Chou { 468*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = bus->sysdata; 469*9aa0cb68SJacky Chou u32 cfg_val; 470*9aa0cb68SJacky Chou 471*9aa0cb68SJacky Chou cfg_val = ASPEED_CFGI_BYTE_EN(TLP_HEADER_BYTE_EN(size, where)) | 472*9aa0cb68SJacky Chou (where & ~3); 473*9aa0cb68SJacky Chou if (write) 474*9aa0cb68SJacky Chou cfg_val |= ASPEED_CFGI_WRITE; 475*9aa0cb68SJacky Chou writel(cfg_val, pcie->reg + ASPEED_H2X_CFGI_TLP); 476*9aa0cb68SJacky Chou 477*9aa0cb68SJacky Chou writel(TLP_SET_VALUE(*val, size, where), 478*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_CFGI_WR_DATA); 479*9aa0cb68SJacky Chou writel(ASPEED_CFGI_TLP_FIRE, pcie->reg + ASPEED_H2X_CFGI_CTRL); 480*9aa0cb68SJacky Chou *val = readl(pcie->reg + ASPEED_H2X_CFGI_RET_DATA); 481*9aa0cb68SJacky Chou *val = TLP_GET_VALUE(*val, size, where); 482*9aa0cb68SJacky Chou 483*9aa0cb68SJacky Chou return PCIBIOS_SUCCESSFUL; 484*9aa0cb68SJacky Chou } 485*9aa0cb68SJacky Chou 486*9aa0cb68SJacky Chou static int aspeed_ast2700_child_config(struct pci_bus *bus, unsigned int devfn, 487*9aa0cb68SJacky Chou int where, int size, u32 *val, 488*9aa0cb68SJacky Chou bool write) 489*9aa0cb68SJacky Chou { 490*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = bus->sysdata; 491*9aa0cb68SJacky Chou u32 bdf_offset, status, cfg_val; 492*9aa0cb68SJacky Chou int ret; 493*9aa0cb68SJacky Chou 494*9aa0cb68SJacky Chou bdf_offset = aspeed_pcie_get_bdf_offset(bus, devfn, where); 495*9aa0cb68SJacky Chou 496*9aa0cb68SJacky Chou cfg_val = CFG_PAYLOAD_SIZE; 497*9aa0cb68SJacky Chou if (write) 498*9aa0cb68SJacky Chou cfg_val |= (bus->number == (pcie->root_bus_nr + 1)) ? 499*9aa0cb68SJacky Chou CFG0_WRITE_FMTTYPE : 500*9aa0cb68SJacky Chou CFG1_WRITE_FMTTYPE; 501*9aa0cb68SJacky Chou else 502*9aa0cb68SJacky Chou cfg_val |= (bus->number == (pcie->root_bus_nr + 1)) ? 503*9aa0cb68SJacky Chou CFG0_READ_FMTTYPE : 504*9aa0cb68SJacky Chou CFG1_READ_FMTTYPE; 505*9aa0cb68SJacky Chou writel(cfg_val, pcie->reg + ASPEED_H2X_CFGE_TLP_1ST); 506*9aa0cb68SJacky Chou 507*9aa0cb68SJacky Chou cfg_val = AST2700_TX_DESC1_VALUE | 508*9aa0cb68SJacky Chou FIELD_PREP(GENMASK(11, 8), pcie->tx_tag) | 509*9aa0cb68SJacky Chou TLP_HEADER_BYTE_EN(size, where); 510*9aa0cb68SJacky Chou writel(cfg_val, pcie->reg + ASPEED_H2X_CFGE_TLP_NEXT); 511*9aa0cb68SJacky Chou 512*9aa0cb68SJacky Chou writel(bdf_offset, pcie->reg + ASPEED_H2X_CFGE_TLP_NEXT); 513*9aa0cb68SJacky Chou if (write) 514*9aa0cb68SJacky Chou writel(TLP_SET_VALUE(*val, size, where), 515*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_CFGE_TLP_NEXT); 516*9aa0cb68SJacky Chou writel(ASPEED_CFGE_TX_IDLE | ASPEED_CFGE_RX_BUSY, 517*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_CFGE_INT_STS); 518*9aa0cb68SJacky Chou writel(ASPEED_CFGE_TLP_FIRE, pcie->reg + ASPEED_H2X_CFGE_CTRL); 519*9aa0cb68SJacky Chou 520*9aa0cb68SJacky Chou ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_CFGE_INT_STS, status, 521*9aa0cb68SJacky Chou (status & ASPEED_CFGE_TX_IDLE), 0, 50); 522*9aa0cb68SJacky Chou if (ret) { 523*9aa0cb68SJacky Chou dev_err(pcie->dev, 524*9aa0cb68SJacky Chou "%02x:%02x.%d CR tx timeout sts: 0x%08x\n", 525*9aa0cb68SJacky Chou bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), status); 526*9aa0cb68SJacky Chou ret = PCIBIOS_SET_FAILED; 527*9aa0cb68SJacky Chou PCI_SET_ERROR_RESPONSE(val); 528*9aa0cb68SJacky Chou goto out; 529*9aa0cb68SJacky Chou } 530*9aa0cb68SJacky Chou 531*9aa0cb68SJacky Chou ret = readl_poll_timeout(pcie->reg + ASPEED_H2X_CFGE_INT_STS, status, 532*9aa0cb68SJacky Chou (status & ASPEED_CFGE_RX_BUSY), 0, 50); 533*9aa0cb68SJacky Chou if (ret) { 534*9aa0cb68SJacky Chou dev_err(pcie->dev, 535*9aa0cb68SJacky Chou "%02x:%02x.%d CR rx timeout sts: 0x%08x\n", 536*9aa0cb68SJacky Chou bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), status); 537*9aa0cb68SJacky Chou ret = PCIBIOS_SET_FAILED; 538*9aa0cb68SJacky Chou PCI_SET_ERROR_RESPONSE(val); 539*9aa0cb68SJacky Chou goto out; 540*9aa0cb68SJacky Chou } 541*9aa0cb68SJacky Chou *val = readl(pcie->reg + ASPEED_H2X_CFGE_RET_DATA); 542*9aa0cb68SJacky Chou *val = TLP_GET_VALUE(*val, size, where); 543*9aa0cb68SJacky Chou 544*9aa0cb68SJacky Chou ret = PCIBIOS_SUCCESSFUL; 545*9aa0cb68SJacky Chou out: 546*9aa0cb68SJacky Chou writel(status, pcie->reg + ASPEED_H2X_CFGE_INT_STS); 547*9aa0cb68SJacky Chou pcie->tx_tag = (pcie->tx_tag + 1) % 0xf; 548*9aa0cb68SJacky Chou return ret; 549*9aa0cb68SJacky Chou } 550*9aa0cb68SJacky Chou 551*9aa0cb68SJacky Chou static int aspeed_ast2700_rd_conf(struct pci_bus *bus, unsigned int devfn, 552*9aa0cb68SJacky Chou int where, int size, u32 *val) 553*9aa0cb68SJacky Chou { 554*9aa0cb68SJacky Chou /* 555*9aa0cb68SJacky Chou * AST2700 has only one Root Port on the root bus. 556*9aa0cb68SJacky Chou */ 557*9aa0cb68SJacky Chou if (devfn != 0) 558*9aa0cb68SJacky Chou return PCIBIOS_DEVICE_NOT_FOUND; 559*9aa0cb68SJacky Chou 560*9aa0cb68SJacky Chou return aspeed_ast2700_config(bus, devfn, where, size, val, false); 561*9aa0cb68SJacky Chou } 562*9aa0cb68SJacky Chou 563*9aa0cb68SJacky Chou static int aspeed_ast2700_child_rd_conf(struct pci_bus *bus, unsigned int devfn, 564*9aa0cb68SJacky Chou int where, int size, u32 *val) 565*9aa0cb68SJacky Chou { 566*9aa0cb68SJacky Chou return aspeed_ast2700_child_config(bus, devfn, where, size, val, false); 567*9aa0cb68SJacky Chou } 568*9aa0cb68SJacky Chou 569*9aa0cb68SJacky Chou static int aspeed_ast2700_wr_conf(struct pci_bus *bus, unsigned int devfn, 570*9aa0cb68SJacky Chou int where, int size, u32 val) 571*9aa0cb68SJacky Chou { 572*9aa0cb68SJacky Chou /* 573*9aa0cb68SJacky Chou * AST2700 has only one Root Port on the root bus. 574*9aa0cb68SJacky Chou */ 575*9aa0cb68SJacky Chou if (devfn != 0) 576*9aa0cb68SJacky Chou return PCIBIOS_DEVICE_NOT_FOUND; 577*9aa0cb68SJacky Chou 578*9aa0cb68SJacky Chou return aspeed_ast2700_config(bus, devfn, where, size, &val, true); 579*9aa0cb68SJacky Chou } 580*9aa0cb68SJacky Chou 581*9aa0cb68SJacky Chou static int aspeed_ast2700_child_wr_conf(struct pci_bus *bus, unsigned int devfn, 582*9aa0cb68SJacky Chou int where, int size, u32 val) 583*9aa0cb68SJacky Chou { 584*9aa0cb68SJacky Chou return aspeed_ast2700_child_config(bus, devfn, where, size, &val, true); 585*9aa0cb68SJacky Chou } 586*9aa0cb68SJacky Chou 587*9aa0cb68SJacky Chou static struct pci_ops aspeed_ast2600_pcie_ops = { 588*9aa0cb68SJacky Chou .read = aspeed_ast2600_rd_conf, 589*9aa0cb68SJacky Chou .write = aspeed_ast2600_wr_conf, 590*9aa0cb68SJacky Chou }; 591*9aa0cb68SJacky Chou 592*9aa0cb68SJacky Chou static struct pci_ops aspeed_ast2600_pcie_child_ops = { 593*9aa0cb68SJacky Chou .read = aspeed_ast2600_child_rd_conf, 594*9aa0cb68SJacky Chou .write = aspeed_ast2600_child_wr_conf, 595*9aa0cb68SJacky Chou }; 596*9aa0cb68SJacky Chou 597*9aa0cb68SJacky Chou static struct pci_ops aspeed_ast2700_pcie_ops = { 598*9aa0cb68SJacky Chou .read = aspeed_ast2700_rd_conf, 599*9aa0cb68SJacky Chou .write = aspeed_ast2700_wr_conf, 600*9aa0cb68SJacky Chou }; 601*9aa0cb68SJacky Chou 602*9aa0cb68SJacky Chou static struct pci_ops aspeed_ast2700_pcie_child_ops = { 603*9aa0cb68SJacky Chou .read = aspeed_ast2700_child_rd_conf, 604*9aa0cb68SJacky Chou .write = aspeed_ast2700_child_wr_conf, 605*9aa0cb68SJacky Chou }; 606*9aa0cb68SJacky Chou 607*9aa0cb68SJacky Chou static void aspeed_irq_compose_msi_msg(struct irq_data *data, 608*9aa0cb68SJacky Chou struct msi_msg *msg) 609*9aa0cb68SJacky Chou { 610*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(data); 611*9aa0cb68SJacky Chou 612*9aa0cb68SJacky Chou msg->address_hi = 0; 613*9aa0cb68SJacky Chou msg->address_lo = pcie->platform->msi_address; 614*9aa0cb68SJacky Chou msg->data = data->hwirq; 615*9aa0cb68SJacky Chou } 616*9aa0cb68SJacky Chou 617*9aa0cb68SJacky Chou static struct irq_chip aspeed_msi_bottom_irq_chip = { 618*9aa0cb68SJacky Chou .name = "ASPEED MSI", 619*9aa0cb68SJacky Chou .irq_compose_msi_msg = aspeed_irq_compose_msi_msg, 620*9aa0cb68SJacky Chou }; 621*9aa0cb68SJacky Chou 622*9aa0cb68SJacky Chou static int aspeed_irq_msi_domain_alloc(struct irq_domain *domain, 623*9aa0cb68SJacky Chou unsigned int virq, unsigned int nr_irqs, 624*9aa0cb68SJacky Chou void *args) 625*9aa0cb68SJacky Chou { 626*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = domain->host_data; 627*9aa0cb68SJacky Chou int bit; 628*9aa0cb68SJacky Chou int i; 629*9aa0cb68SJacky Chou 630*9aa0cb68SJacky Chou guard(mutex)(&pcie->lock); 631*9aa0cb68SJacky Chou 632*9aa0cb68SJacky Chou bit = bitmap_find_free_region(pcie->msi_irq_in_use, MAX_MSI_HOST_IRQS, 633*9aa0cb68SJacky Chou get_count_order(nr_irqs)); 634*9aa0cb68SJacky Chou 635*9aa0cb68SJacky Chou if (bit < 0) 636*9aa0cb68SJacky Chou return -ENOSPC; 637*9aa0cb68SJacky Chou 638*9aa0cb68SJacky Chou for (i = 0; i < nr_irqs; i++) { 639*9aa0cb68SJacky Chou irq_domain_set_info(domain, virq + i, bit + i, 640*9aa0cb68SJacky Chou &aspeed_msi_bottom_irq_chip, 641*9aa0cb68SJacky Chou domain->host_data, handle_simple_irq, NULL, 642*9aa0cb68SJacky Chou NULL); 643*9aa0cb68SJacky Chou } 644*9aa0cb68SJacky Chou 645*9aa0cb68SJacky Chou return 0; 646*9aa0cb68SJacky Chou } 647*9aa0cb68SJacky Chou 648*9aa0cb68SJacky Chou static void aspeed_irq_msi_domain_free(struct irq_domain *domain, 649*9aa0cb68SJacky Chou unsigned int virq, unsigned int nr_irqs) 650*9aa0cb68SJacky Chou { 651*9aa0cb68SJacky Chou struct irq_data *data = irq_domain_get_irq_data(domain, virq); 652*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = irq_data_get_irq_chip_data(data); 653*9aa0cb68SJacky Chou 654*9aa0cb68SJacky Chou guard(mutex)(&pcie->lock); 655*9aa0cb68SJacky Chou 656*9aa0cb68SJacky Chou bitmap_release_region(pcie->msi_irq_in_use, data->hwirq, 657*9aa0cb68SJacky Chou get_count_order(nr_irqs)); 658*9aa0cb68SJacky Chou } 659*9aa0cb68SJacky Chou 660*9aa0cb68SJacky Chou static const struct irq_domain_ops aspeed_msi_domain_ops = { 661*9aa0cb68SJacky Chou .alloc = aspeed_irq_msi_domain_alloc, 662*9aa0cb68SJacky Chou .free = aspeed_irq_msi_domain_free, 663*9aa0cb68SJacky Chou }; 664*9aa0cb68SJacky Chou 665*9aa0cb68SJacky Chou #define ASPEED_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ 666*9aa0cb68SJacky Chou MSI_FLAG_USE_DEF_CHIP_OPS | \ 667*9aa0cb68SJacky Chou MSI_FLAG_NO_AFFINITY) 668*9aa0cb68SJacky Chou 669*9aa0cb68SJacky Chou #define ASPEED_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ 670*9aa0cb68SJacky Chou MSI_FLAG_MULTI_PCI_MSI | \ 671*9aa0cb68SJacky Chou MSI_FLAG_PCI_MSIX) 672*9aa0cb68SJacky Chou 673*9aa0cb68SJacky Chou static const struct msi_parent_ops aspeed_msi_parent_ops = { 674*9aa0cb68SJacky Chou .required_flags = ASPEED_MSI_FLAGS_REQUIRED, 675*9aa0cb68SJacky Chou .supported_flags = ASPEED_MSI_FLAGS_SUPPORTED, 676*9aa0cb68SJacky Chou .bus_select_token = DOMAIN_BUS_PCI_MSI, 677*9aa0cb68SJacky Chou .chip_flags = MSI_CHIP_FLAG_SET_ACK, 678*9aa0cb68SJacky Chou .prefix = "ASPEED-", 679*9aa0cb68SJacky Chou .init_dev_msi_info = msi_lib_init_dev_msi_info, 680*9aa0cb68SJacky Chou }; 681*9aa0cb68SJacky Chou 682*9aa0cb68SJacky Chou static int aspeed_pcie_msi_init(struct aspeed_pcie *pcie) 683*9aa0cb68SJacky Chou { 684*9aa0cb68SJacky Chou writel(~0, pcie->reg + pcie->platform->reg_msi_en); 685*9aa0cb68SJacky Chou writel(~0, pcie->reg + pcie->platform->reg_msi_en + 0x04); 686*9aa0cb68SJacky Chou writel(~0, pcie->reg + pcie->platform->reg_msi_sts); 687*9aa0cb68SJacky Chou writel(~0, pcie->reg + pcie->platform->reg_msi_sts + 0x04); 688*9aa0cb68SJacky Chou 689*9aa0cb68SJacky Chou struct irq_domain_info info = { 690*9aa0cb68SJacky Chou .fwnode = dev_fwnode(pcie->dev), 691*9aa0cb68SJacky Chou .ops = &aspeed_msi_domain_ops, 692*9aa0cb68SJacky Chou .host_data = pcie, 693*9aa0cb68SJacky Chou .size = MAX_MSI_HOST_IRQS, 694*9aa0cb68SJacky Chou }; 695*9aa0cb68SJacky Chou 696*9aa0cb68SJacky Chou pcie->msi_domain = msi_create_parent_irq_domain(&info, 697*9aa0cb68SJacky Chou &aspeed_msi_parent_ops); 698*9aa0cb68SJacky Chou if (!pcie->msi_domain) 699*9aa0cb68SJacky Chou return dev_err_probe(pcie->dev, -ENOMEM, 700*9aa0cb68SJacky Chou "failed to create MSI domain\n"); 701*9aa0cb68SJacky Chou 702*9aa0cb68SJacky Chou return 0; 703*9aa0cb68SJacky Chou } 704*9aa0cb68SJacky Chou 705*9aa0cb68SJacky Chou static void aspeed_pcie_msi_free(struct aspeed_pcie *pcie) 706*9aa0cb68SJacky Chou { 707*9aa0cb68SJacky Chou if (pcie->msi_domain) { 708*9aa0cb68SJacky Chou irq_domain_remove(pcie->msi_domain); 709*9aa0cb68SJacky Chou pcie->msi_domain = NULL; 710*9aa0cb68SJacky Chou } 711*9aa0cb68SJacky Chou } 712*9aa0cb68SJacky Chou 713*9aa0cb68SJacky Chou static void aspeed_pcie_irq_domain_free(void *d) 714*9aa0cb68SJacky Chou { 715*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = d; 716*9aa0cb68SJacky Chou 717*9aa0cb68SJacky Chou if (pcie->intx_domain) { 718*9aa0cb68SJacky Chou irq_domain_remove(pcie->intx_domain); 719*9aa0cb68SJacky Chou pcie->intx_domain = NULL; 720*9aa0cb68SJacky Chou } 721*9aa0cb68SJacky Chou aspeed_pcie_msi_free(pcie); 722*9aa0cb68SJacky Chou } 723*9aa0cb68SJacky Chou 724*9aa0cb68SJacky Chou static int aspeed_pcie_init_irq_domain(struct aspeed_pcie *pcie) 725*9aa0cb68SJacky Chou { 726*9aa0cb68SJacky Chou int ret; 727*9aa0cb68SJacky Chou 728*9aa0cb68SJacky Chou pcie->intx_domain = irq_domain_add_linear(pcie->dev->of_node, 729*9aa0cb68SJacky Chou PCI_NUM_INTX, 730*9aa0cb68SJacky Chou &aspeed_intx_domain_ops, 731*9aa0cb68SJacky Chou pcie); 732*9aa0cb68SJacky Chou if (!pcie->intx_domain) { 733*9aa0cb68SJacky Chou ret = dev_err_probe(pcie->dev, -ENOMEM, 734*9aa0cb68SJacky Chou "failed to get INTx IRQ domain\n"); 735*9aa0cb68SJacky Chou goto err; 736*9aa0cb68SJacky Chou } 737*9aa0cb68SJacky Chou 738*9aa0cb68SJacky Chou writel(0, pcie->reg + pcie->platform->reg_intx_en); 739*9aa0cb68SJacky Chou writel(~0, pcie->reg + pcie->platform->reg_intx_sts); 740*9aa0cb68SJacky Chou 741*9aa0cb68SJacky Chou ret = aspeed_pcie_msi_init(pcie); 742*9aa0cb68SJacky Chou if (ret) 743*9aa0cb68SJacky Chou goto err; 744*9aa0cb68SJacky Chou 745*9aa0cb68SJacky Chou return 0; 746*9aa0cb68SJacky Chou err: 747*9aa0cb68SJacky Chou aspeed_pcie_irq_domain_free(pcie); 748*9aa0cb68SJacky Chou return ret; 749*9aa0cb68SJacky Chou } 750*9aa0cb68SJacky Chou 751*9aa0cb68SJacky Chou static int aspeed_pcie_port_init(struct aspeed_pcie_port *port) 752*9aa0cb68SJacky Chou { 753*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = port->pcie; 754*9aa0cb68SJacky Chou struct device *dev = pcie->dev; 755*9aa0cb68SJacky Chou int ret; 756*9aa0cb68SJacky Chou 757*9aa0cb68SJacky Chou ret = clk_prepare_enable(port->clk); 758*9aa0cb68SJacky Chou if (ret) 759*9aa0cb68SJacky Chou return dev_err_probe(dev, ret, 760*9aa0cb68SJacky Chou "failed to set clock for slot (%d)\n", 761*9aa0cb68SJacky Chou port->slot); 762*9aa0cb68SJacky Chou 763*9aa0cb68SJacky Chou ret = phy_init(port->phy); 764*9aa0cb68SJacky Chou if (ret) 765*9aa0cb68SJacky Chou return dev_err_probe(dev, ret, 766*9aa0cb68SJacky Chou "failed to init phy pcie for slot (%d)\n", 767*9aa0cb68SJacky Chou port->slot); 768*9aa0cb68SJacky Chou 769*9aa0cb68SJacky Chou ret = phy_set_mode_ext(port->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC); 770*9aa0cb68SJacky Chou if (ret) 771*9aa0cb68SJacky Chou return dev_err_probe(dev, ret, 772*9aa0cb68SJacky Chou "failed to set phy mode for slot (%d)\n", 773*9aa0cb68SJacky Chou port->slot); 774*9aa0cb68SJacky Chou 775*9aa0cb68SJacky Chou reset_control_deassert(port->perst); 776*9aa0cb68SJacky Chou msleep(PCIE_RESET_CONFIG_WAIT_MS); 777*9aa0cb68SJacky Chou 778*9aa0cb68SJacky Chou return 0; 779*9aa0cb68SJacky Chou } 780*9aa0cb68SJacky Chou 781*9aa0cb68SJacky Chou static void aspeed_host_reset(struct aspeed_pcie *pcie) 782*9aa0cb68SJacky Chou { 783*9aa0cb68SJacky Chou reset_control_assert(pcie->h2xrst); 784*9aa0cb68SJacky Chou mdelay(ASPEED_RESET_RC_WAIT_MS); 785*9aa0cb68SJacky Chou reset_control_deassert(pcie->h2xrst); 786*9aa0cb68SJacky Chou } 787*9aa0cb68SJacky Chou 788*9aa0cb68SJacky Chou static void aspeed_pcie_map_ranges(struct aspeed_pcie *pcie) 789*9aa0cb68SJacky Chou { 790*9aa0cb68SJacky Chou struct pci_host_bridge *bridge = pcie->host; 791*9aa0cb68SJacky Chou struct resource_entry *window; 792*9aa0cb68SJacky Chou 793*9aa0cb68SJacky Chou resource_list_for_each_entry(window, &bridge->windows) { 794*9aa0cb68SJacky Chou u64 pci_addr; 795*9aa0cb68SJacky Chou 796*9aa0cb68SJacky Chou if (resource_type(window->res) != IORESOURCE_MEM) 797*9aa0cb68SJacky Chou continue; 798*9aa0cb68SJacky Chou 799*9aa0cb68SJacky Chou pci_addr = window->res->start - window->offset; 800*9aa0cb68SJacky Chou pcie->platform->pcie_map_ranges(pcie, pci_addr); 801*9aa0cb68SJacky Chou break; 802*9aa0cb68SJacky Chou } 803*9aa0cb68SJacky Chou } 804*9aa0cb68SJacky Chou 805*9aa0cb68SJacky Chou static void aspeed_ast2600_pcie_map_ranges(struct aspeed_pcie *pcie, 806*9aa0cb68SJacky Chou u64 pci_addr) 807*9aa0cb68SJacky Chou { 808*9aa0cb68SJacky Chou u32 pci_addr_lo = pci_addr & GENMASK(31, 0); 809*9aa0cb68SJacky Chou u32 pci_addr_hi = (pci_addr >> 32) & GENMASK(31, 0); 810*9aa0cb68SJacky Chou 811*9aa0cb68SJacky Chou pci_addr_lo >>= 16; 812*9aa0cb68SJacky Chou writel(ASPEED_AHB_REMAP_LO_ADDR(pci_addr_lo) | 813*9aa0cb68SJacky Chou ASPEED_AHB_MASK_LO_ADDR(0xe00), 814*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG0); 815*9aa0cb68SJacky Chou writel(ASPEED_AHB_REMAP_HI_ADDR(pci_addr_hi), 816*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG1); 817*9aa0cb68SJacky Chou writel(ASPEED_AHB_MASK_HI_ADDR(~0), 818*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_AHB_ADDR_CONFIG2); 819*9aa0cb68SJacky Chou } 820*9aa0cb68SJacky Chou 821*9aa0cb68SJacky Chou static int aspeed_ast2600_setup(struct platform_device *pdev) 822*9aa0cb68SJacky Chou { 823*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = platform_get_drvdata(pdev); 824*9aa0cb68SJacky Chou struct device *dev = pcie->dev; 825*9aa0cb68SJacky Chou 826*9aa0cb68SJacky Chou pcie->ahbc = syscon_regmap_lookup_by_phandle(dev->of_node, 827*9aa0cb68SJacky Chou "aspeed,ahbc"); 828*9aa0cb68SJacky Chou if (IS_ERR(pcie->ahbc)) 829*9aa0cb68SJacky Chou return dev_err_probe(dev, PTR_ERR(pcie->ahbc), 830*9aa0cb68SJacky Chou "failed to map ahbc base\n"); 831*9aa0cb68SJacky Chou 832*9aa0cb68SJacky Chou aspeed_host_reset(pcie); 833*9aa0cb68SJacky Chou 834*9aa0cb68SJacky Chou regmap_write(pcie->ahbc, ASPEED_AHBC_KEY, ASPEED_AHBC_UNLOCK_KEY); 835*9aa0cb68SJacky Chou regmap_update_bits(pcie->ahbc, ASPEED_AHBC_ADDR_MAPPING, 836*9aa0cb68SJacky Chou ASPEED_PCIE_RC_MEMORY_EN, ASPEED_PCIE_RC_MEMORY_EN); 837*9aa0cb68SJacky Chou regmap_write(pcie->ahbc, ASPEED_AHBC_KEY, ASPEED_AHBC_UNLOCK); 838*9aa0cb68SJacky Chou 839*9aa0cb68SJacky Chou writel(ASPEED_H2X_BRIDGE_EN, pcie->reg + ASPEED_H2X_CTRL); 840*9aa0cb68SJacky Chou 841*9aa0cb68SJacky Chou writel(ASPEED_PCIE_RX_DMA_EN | ASPEED_PCIE_RX_LINEAR | 842*9aa0cb68SJacky Chou ASPEED_PCIE_RX_MSI_SEL | ASPEED_PCIE_RX_MSI_EN | 843*9aa0cb68SJacky Chou ASPEED_PCIE_WAIT_RX_TLP_CLR | ASPEED_PCIE_RC_RX_ENABLE | 844*9aa0cb68SJacky Chou ASPEED_PCIE_RC_ENABLE, 845*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_DEV_CTRL); 846*9aa0cb68SJacky Chou 847*9aa0cb68SJacky Chou writel(ASPEED_RC_TLP_TX_TAG_NUM, pcie->reg + ASPEED_H2X_DEV_TX_TAG); 848*9aa0cb68SJacky Chou 849*9aa0cb68SJacky Chou pcie->host->ops = &aspeed_ast2600_pcie_ops; 850*9aa0cb68SJacky Chou pcie->host->child_ops = &aspeed_ast2600_pcie_child_ops; 851*9aa0cb68SJacky Chou 852*9aa0cb68SJacky Chou return 0; 853*9aa0cb68SJacky Chou } 854*9aa0cb68SJacky Chou 855*9aa0cb68SJacky Chou static void aspeed_ast2700_pcie_map_ranges(struct aspeed_pcie *pcie, 856*9aa0cb68SJacky Chou u64 pci_addr) 857*9aa0cb68SJacky Chou { 858*9aa0cb68SJacky Chou writel(ASPEED_REMAP_PCI_ADDR_31_12(pci_addr), 859*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_REMAP_PCI_ADDR_LO); 860*9aa0cb68SJacky Chou writel(ASPEED_REMAP_PCI_ADDR_63_32(pci_addr), 861*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_REMAP_PCI_ADDR_HI); 862*9aa0cb68SJacky Chou } 863*9aa0cb68SJacky Chou 864*9aa0cb68SJacky Chou static int aspeed_ast2700_setup(struct platform_device *pdev) 865*9aa0cb68SJacky Chou { 866*9aa0cb68SJacky Chou struct aspeed_pcie *pcie = platform_get_drvdata(pdev); 867*9aa0cb68SJacky Chou struct device *dev = pcie->dev; 868*9aa0cb68SJacky Chou 869*9aa0cb68SJacky Chou pcie->cfg = syscon_regmap_lookup_by_phandle(dev->of_node, 870*9aa0cb68SJacky Chou "aspeed,pciecfg"); 871*9aa0cb68SJacky Chou if (IS_ERR(pcie->cfg)) 872*9aa0cb68SJacky Chou return dev_err_probe(dev, PTR_ERR(pcie->cfg), 873*9aa0cb68SJacky Chou "failed to map pciecfg base\n"); 874*9aa0cb68SJacky Chou 875*9aa0cb68SJacky Chou regmap_update_bits(pcie->cfg, ASPEED_SCU_60, 876*9aa0cb68SJacky Chou ASPEED_RC_E2M_PATH_EN | ASPEED_RC_H2XS_PATH_EN | 877*9aa0cb68SJacky Chou ASPEED_RC_H2XD_PATH_EN | ASPEED_RC_H2XX_PATH_EN | 878*9aa0cb68SJacky Chou ASPEED_RC_UPSTREAM_MEM_EN, 879*9aa0cb68SJacky Chou ASPEED_RC_E2M_PATH_EN | ASPEED_RC_H2XS_PATH_EN | 880*9aa0cb68SJacky Chou ASPEED_RC_H2XD_PATH_EN | ASPEED_RC_H2XX_PATH_EN | 881*9aa0cb68SJacky Chou ASPEED_RC_UPSTREAM_MEM_EN); 882*9aa0cb68SJacky Chou regmap_write(pcie->cfg, ASPEED_SCU_64, 883*9aa0cb68SJacky Chou ASPEED_RC0_DECODE_DMA_BASE(0) | 884*9aa0cb68SJacky Chou ASPEED_RC0_DECODE_DMA_LIMIT(0xff) | 885*9aa0cb68SJacky Chou ASPEED_RC1_DECODE_DMA_BASE(0) | 886*9aa0cb68SJacky Chou ASPEED_RC1_DECODE_DMA_LIMIT(0xff)); 887*9aa0cb68SJacky Chou regmap_write(pcie->cfg, ASPEED_SCU_70, ASPEED_DISABLE_EP_FUNC); 888*9aa0cb68SJacky Chou 889*9aa0cb68SJacky Chou aspeed_host_reset(pcie); 890*9aa0cb68SJacky Chou 891*9aa0cb68SJacky Chou writel(0, pcie->reg + ASPEED_H2X_CTRL); 892*9aa0cb68SJacky Chou writel(ASPEED_H2X_BRIDGE_EN | ASPEED_H2X_BRIDGE_DIRECT_EN, 893*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_CTRL); 894*9aa0cb68SJacky Chou 895*9aa0cb68SJacky Chou /* Prepare for 64-bit BAR pref */ 896*9aa0cb68SJacky Chou writel(ASPEED_REMAP_PREF_ADDR_63_32(0x3), 897*9aa0cb68SJacky Chou pcie->reg + ASPEED_H2X_REMAP_PREF_ADDR); 898*9aa0cb68SJacky Chou 899*9aa0cb68SJacky Chou pcie->host->ops = &aspeed_ast2700_pcie_ops; 900*9aa0cb68SJacky Chou pcie->host->child_ops = &aspeed_ast2700_pcie_child_ops; 901*9aa0cb68SJacky Chou pcie->clear_msi_twice = true; 902*9aa0cb68SJacky Chou 903*9aa0cb68SJacky Chou return 0; 904*9aa0cb68SJacky Chou } 905*9aa0cb68SJacky Chou 906*9aa0cb68SJacky Chou static void aspeed_pcie_reset_release(void *d) 907*9aa0cb68SJacky Chou { 908*9aa0cb68SJacky Chou struct reset_control *perst = d; 909*9aa0cb68SJacky Chou 910*9aa0cb68SJacky Chou if (!perst) 911*9aa0cb68SJacky Chou return; 912*9aa0cb68SJacky Chou 913*9aa0cb68SJacky Chou reset_control_put(perst); 914*9aa0cb68SJacky Chou } 915*9aa0cb68SJacky Chou 916*9aa0cb68SJacky Chou static int aspeed_pcie_parse_port(struct aspeed_pcie *pcie, 917*9aa0cb68SJacky Chou struct device_node *node, 918*9aa0cb68SJacky Chou int slot) 919*9aa0cb68SJacky Chou { 920*9aa0cb68SJacky Chou struct aspeed_pcie_port *port; 921*9aa0cb68SJacky Chou struct device *dev = pcie->dev; 922*9aa0cb68SJacky Chou int ret; 923*9aa0cb68SJacky Chou 924*9aa0cb68SJacky Chou port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); 925*9aa0cb68SJacky Chou if (!port) 926*9aa0cb68SJacky Chou return -ENOMEM; 927*9aa0cb68SJacky Chou 928*9aa0cb68SJacky Chou port->clk = devm_get_clk_from_child(dev, node, NULL); 929*9aa0cb68SJacky Chou if (IS_ERR(port->clk)) 930*9aa0cb68SJacky Chou return dev_err_probe(dev, PTR_ERR(port->clk), 931*9aa0cb68SJacky Chou "failed to get pcie%d clock\n", slot); 932*9aa0cb68SJacky Chou 933*9aa0cb68SJacky Chou port->phy = devm_of_phy_get(dev, node, NULL); 934*9aa0cb68SJacky Chou if (IS_ERR(port->phy)) 935*9aa0cb68SJacky Chou return dev_err_probe(dev, PTR_ERR(port->phy), 936*9aa0cb68SJacky Chou "failed to get phy pcie%d\n", slot); 937*9aa0cb68SJacky Chou 938*9aa0cb68SJacky Chou port->perst = of_reset_control_get_exclusive(node, "perst"); 939*9aa0cb68SJacky Chou if (IS_ERR(port->perst)) 940*9aa0cb68SJacky Chou return dev_err_probe(dev, PTR_ERR(port->perst), 941*9aa0cb68SJacky Chou "failed to get pcie%d reset control\n", 942*9aa0cb68SJacky Chou slot); 943*9aa0cb68SJacky Chou ret = devm_add_action_or_reset(dev, aspeed_pcie_reset_release, 944*9aa0cb68SJacky Chou port->perst); 945*9aa0cb68SJacky Chou if (ret) 946*9aa0cb68SJacky Chou return ret; 947*9aa0cb68SJacky Chou reset_control_assert(port->perst); 948*9aa0cb68SJacky Chou 949*9aa0cb68SJacky Chou port->slot = slot; 950*9aa0cb68SJacky Chou port->pcie = pcie; 951*9aa0cb68SJacky Chou 952*9aa0cb68SJacky Chou INIT_LIST_HEAD(&port->list); 953*9aa0cb68SJacky Chou list_add_tail(&port->list, &pcie->ports); 954*9aa0cb68SJacky Chou 955*9aa0cb68SJacky Chou ret = aspeed_pcie_port_init(port); 956*9aa0cb68SJacky Chou if (ret) 957*9aa0cb68SJacky Chou return ret; 958*9aa0cb68SJacky Chou 959*9aa0cb68SJacky Chou return 0; 960*9aa0cb68SJacky Chou } 961*9aa0cb68SJacky Chou 962*9aa0cb68SJacky Chou static int aspeed_pcie_parse_dt(struct aspeed_pcie *pcie) 963*9aa0cb68SJacky Chou { 964*9aa0cb68SJacky Chou struct device *dev = pcie->dev; 965*9aa0cb68SJacky Chou struct device_node *node = dev->of_node; 966*9aa0cb68SJacky Chou int ret; 967*9aa0cb68SJacky Chou 968*9aa0cb68SJacky Chou for_each_available_child_of_node_scoped(node, child) { 969*9aa0cb68SJacky Chou int slot; 970*9aa0cb68SJacky Chou const char *type; 971*9aa0cb68SJacky Chou 972*9aa0cb68SJacky Chou ret = of_property_read_string(child, "device_type", &type); 973*9aa0cb68SJacky Chou if (ret || strcmp(type, "pci")) 974*9aa0cb68SJacky Chou continue; 975*9aa0cb68SJacky Chou 976*9aa0cb68SJacky Chou ret = of_pci_get_devfn(child); 977*9aa0cb68SJacky Chou if (ret < 0) 978*9aa0cb68SJacky Chou return dev_err_probe(dev, ret, 979*9aa0cb68SJacky Chou "failed to parse devfn\n"); 980*9aa0cb68SJacky Chou 981*9aa0cb68SJacky Chou slot = PCI_SLOT(ret); 982*9aa0cb68SJacky Chou 983*9aa0cb68SJacky Chou ret = aspeed_pcie_parse_port(pcie, child, slot); 984*9aa0cb68SJacky Chou if (ret) 985*9aa0cb68SJacky Chou return ret; 986*9aa0cb68SJacky Chou } 987*9aa0cb68SJacky Chou 988*9aa0cb68SJacky Chou if (list_empty(&pcie->ports)) 989*9aa0cb68SJacky Chou return dev_err_probe(dev, -ENODEV, 990*9aa0cb68SJacky Chou "No PCIe port found in DT\n"); 991*9aa0cb68SJacky Chou 992*9aa0cb68SJacky Chou return 0; 993*9aa0cb68SJacky Chou } 994*9aa0cb68SJacky Chou 995*9aa0cb68SJacky Chou static int aspeed_pcie_probe(struct platform_device *pdev) 996*9aa0cb68SJacky Chou { 997*9aa0cb68SJacky Chou struct device *dev = &pdev->dev; 998*9aa0cb68SJacky Chou struct pci_host_bridge *host; 999*9aa0cb68SJacky Chou struct aspeed_pcie *pcie; 1000*9aa0cb68SJacky Chou struct resource_entry *entry; 1001*9aa0cb68SJacky Chou const struct aspeed_pcie_rc_platform *md; 1002*9aa0cb68SJacky Chou int irq, ret; 1003*9aa0cb68SJacky Chou 1004*9aa0cb68SJacky Chou md = of_device_get_match_data(dev); 1005*9aa0cb68SJacky Chou if (!md) 1006*9aa0cb68SJacky Chou return -ENODEV; 1007*9aa0cb68SJacky Chou 1008*9aa0cb68SJacky Chou host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); 1009*9aa0cb68SJacky Chou if (!host) 1010*9aa0cb68SJacky Chou return -ENOMEM; 1011*9aa0cb68SJacky Chou 1012*9aa0cb68SJacky Chou pcie = pci_host_bridge_priv(host); 1013*9aa0cb68SJacky Chou pcie->dev = dev; 1014*9aa0cb68SJacky Chou pcie->tx_tag = 0; 1015*9aa0cb68SJacky Chou platform_set_drvdata(pdev, pcie); 1016*9aa0cb68SJacky Chou 1017*9aa0cb68SJacky Chou pcie->platform = md; 1018*9aa0cb68SJacky Chou pcie->host = host; 1019*9aa0cb68SJacky Chou INIT_LIST_HEAD(&pcie->ports); 1020*9aa0cb68SJacky Chou 1021*9aa0cb68SJacky Chou /* Get root bus num for cfg command to decide tlp type 0 or type 1 */ 1022*9aa0cb68SJacky Chou entry = resource_list_first_type(&host->windows, IORESOURCE_BUS); 1023*9aa0cb68SJacky Chou if (entry) 1024*9aa0cb68SJacky Chou pcie->root_bus_nr = entry->res->start; 1025*9aa0cb68SJacky Chou 1026*9aa0cb68SJacky Chou pcie->reg = devm_platform_ioremap_resource(pdev, 0); 1027*9aa0cb68SJacky Chou if (IS_ERR(pcie->reg)) 1028*9aa0cb68SJacky Chou return PTR_ERR(pcie->reg); 1029*9aa0cb68SJacky Chou 1030*9aa0cb68SJacky Chou pcie->h2xrst = devm_reset_control_get_exclusive(dev, "h2x"); 1031*9aa0cb68SJacky Chou if (IS_ERR(pcie->h2xrst)) 1032*9aa0cb68SJacky Chou return dev_err_probe(dev, PTR_ERR(pcie->h2xrst), 1033*9aa0cb68SJacky Chou "failed to get h2x reset\n"); 1034*9aa0cb68SJacky Chou 1035*9aa0cb68SJacky Chou ret = devm_mutex_init(dev, &pcie->lock); 1036*9aa0cb68SJacky Chou if (ret) 1037*9aa0cb68SJacky Chou return dev_err_probe(dev, ret, "failed to init mutex\n"); 1038*9aa0cb68SJacky Chou 1039*9aa0cb68SJacky Chou ret = pcie->platform->setup(pdev); 1040*9aa0cb68SJacky Chou if (ret) 1041*9aa0cb68SJacky Chou return dev_err_probe(dev, ret, "failed to setup PCIe RC\n"); 1042*9aa0cb68SJacky Chou 1043*9aa0cb68SJacky Chou aspeed_pcie_map_ranges(pcie); 1044*9aa0cb68SJacky Chou 1045*9aa0cb68SJacky Chou ret = aspeed_pcie_parse_dt(pcie); 1046*9aa0cb68SJacky Chou if (ret) 1047*9aa0cb68SJacky Chou return ret; 1048*9aa0cb68SJacky Chou 1049*9aa0cb68SJacky Chou host->sysdata = pcie; 1050*9aa0cb68SJacky Chou 1051*9aa0cb68SJacky Chou ret = aspeed_pcie_init_irq_domain(pcie); 1052*9aa0cb68SJacky Chou if (ret) 1053*9aa0cb68SJacky Chou return ret; 1054*9aa0cb68SJacky Chou 1055*9aa0cb68SJacky Chou irq = platform_get_irq(pdev, 0); 1056*9aa0cb68SJacky Chou if (irq < 0) 1057*9aa0cb68SJacky Chou return irq; 1058*9aa0cb68SJacky Chou 1059*9aa0cb68SJacky Chou ret = devm_add_action_or_reset(dev, aspeed_pcie_irq_domain_free, pcie); 1060*9aa0cb68SJacky Chou if (ret) 1061*9aa0cb68SJacky Chou return ret; 1062*9aa0cb68SJacky Chou 1063*9aa0cb68SJacky Chou ret = devm_request_irq(dev, irq, aspeed_pcie_intr_handler, IRQF_SHARED, 1064*9aa0cb68SJacky Chou dev_name(dev), pcie); 1065*9aa0cb68SJacky Chou if (ret) 1066*9aa0cb68SJacky Chou return ret; 1067*9aa0cb68SJacky Chou 1068*9aa0cb68SJacky Chou return pci_host_probe(host); 1069*9aa0cb68SJacky Chou } 1070*9aa0cb68SJacky Chou 1071*9aa0cb68SJacky Chou static const struct aspeed_pcie_rc_platform pcie_rc_ast2600 = { 1072*9aa0cb68SJacky Chou .setup = aspeed_ast2600_setup, 1073*9aa0cb68SJacky Chou .pcie_map_ranges = aspeed_ast2600_pcie_map_ranges, 1074*9aa0cb68SJacky Chou .reg_intx_en = 0xc4, 1075*9aa0cb68SJacky Chou .reg_intx_sts = 0xc8, 1076*9aa0cb68SJacky Chou .reg_msi_en = 0xe0, 1077*9aa0cb68SJacky Chou .reg_msi_sts = 0xe8, 1078*9aa0cb68SJacky Chou .msi_address = 0x1e77005c, 1079*9aa0cb68SJacky Chou }; 1080*9aa0cb68SJacky Chou 1081*9aa0cb68SJacky Chou static const struct aspeed_pcie_rc_platform pcie_rc_ast2700 = { 1082*9aa0cb68SJacky Chou .setup = aspeed_ast2700_setup, 1083*9aa0cb68SJacky Chou .pcie_map_ranges = aspeed_ast2700_pcie_map_ranges, 1084*9aa0cb68SJacky Chou .reg_intx_en = 0x40, 1085*9aa0cb68SJacky Chou .reg_intx_sts = 0x48, 1086*9aa0cb68SJacky Chou .reg_msi_en = 0x50, 1087*9aa0cb68SJacky Chou .reg_msi_sts = 0x58, 1088*9aa0cb68SJacky Chou .msi_address = 0x000000f0, 1089*9aa0cb68SJacky Chou }; 1090*9aa0cb68SJacky Chou 1091*9aa0cb68SJacky Chou static const struct of_device_id aspeed_pcie_of_match[] = { 1092*9aa0cb68SJacky Chou { .compatible = "aspeed,ast2600-pcie", .data = &pcie_rc_ast2600 }, 1093*9aa0cb68SJacky Chou { .compatible = "aspeed,ast2700-pcie", .data = &pcie_rc_ast2700 }, 1094*9aa0cb68SJacky Chou {} 1095*9aa0cb68SJacky Chou }; 1096*9aa0cb68SJacky Chou 1097*9aa0cb68SJacky Chou static struct platform_driver aspeed_pcie_driver = { 1098*9aa0cb68SJacky Chou .driver = { 1099*9aa0cb68SJacky Chou .name = "aspeed-pcie", 1100*9aa0cb68SJacky Chou .of_match_table = aspeed_pcie_of_match, 1101*9aa0cb68SJacky Chou .suppress_bind_attrs = true, 1102*9aa0cb68SJacky Chou .probe_type = PROBE_PREFER_ASYNCHRONOUS, 1103*9aa0cb68SJacky Chou }, 1104*9aa0cb68SJacky Chou .probe = aspeed_pcie_probe, 1105*9aa0cb68SJacky Chou }; 1106*9aa0cb68SJacky Chou 1107*9aa0cb68SJacky Chou builtin_platform_driver(aspeed_pcie_driver); 1108*9aa0cb68SJacky Chou 1109*9aa0cb68SJacky Chou MODULE_AUTHOR("Jacky Chou <jacky_chou@aspeedtech.com>"); 1110*9aa0cb68SJacky Chou MODULE_DESCRIPTION("ASPEED PCIe Root Complex"); 1111*9aa0cb68SJacky Chou MODULE_LICENSE("GPL"); 1112