diff options
Diffstat (limited to 'drivers/pci/controller/pcie-brcmstb.c')
| -rw-r--r-- | drivers/pci/controller/pcie-brcmstb.c | 444 | 
1 files changed, 381 insertions, 63 deletions
diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index bac63d04297f..bea86899bd5d 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -23,6 +23,7 @@  #include <linux/of_platform.h>  #include <linux/pci.h>  #include <linux/printk.h> +#include <linux/reset.h>  #include <linux/sizes.h>  #include <linux/slab.h>  #include <linux/string.h> @@ -52,8 +53,11 @@  #define  PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK		0x1000  #define  PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK	0x2000  #define  PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK	0x300000 -#define  PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128		0x0 +  #define  PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK		0xf8000000 +#define  PCIE_MISC_MISC_CTRL_SCB1_SIZE_MASK		0x07c00000 +#define  PCIE_MISC_MISC_CTRL_SCB2_SIZE_MASK		0x0000001f +#define  SCB_SIZE_MASK(x) PCIE_MISC_MISC_CTRL_SCB ## x ## _SIZE_MASK  #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO		0x400c  #define PCIE_MEM_WIN0_LO(win)	\ @@ -77,10 +81,12 @@  #define PCIE_MISC_MSI_BAR_CONFIG_HI			0x4048  #define PCIE_MISC_MSI_DATA_CONFIG			0x404c -#define  PCIE_MISC_MSI_DATA_CONFIG_VAL			0xffe06540 +#define  PCIE_MISC_MSI_DATA_CONFIG_VAL_32		0xffe06540 +#define  PCIE_MISC_MSI_DATA_CONFIG_VAL_8		0xfff86540  #define PCIE_MISC_PCIE_CTRL				0x4064  #define  PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK	0x1 +#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK		0x4  #define PCIE_MISC_PCIE_STATUS				0x4068  #define  PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK		0x80 @@ -88,6 +94,9 @@  #define  PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK	0x10  #define  PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK	0x40 +#define PCIE_MISC_REVISION				0x406c +#define  BRCM_PCIE_HW_REV_33				0x0303 +  #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT		0x4070  #define  PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK	0xfff00000  #define  PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK	0xfff0 @@ -108,10 +117,14 @@  #define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK	0x2  #define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK		0x08000000 -#define PCIE_MSI_INTR2_STATUS				0x4500 -#define PCIE_MSI_INTR2_CLR				0x4508 -#define PCIE_MSI_INTR2_MASK_SET				0x4510 -#define PCIE_MSI_INTR2_MASK_CLR				0x4514 + +#define PCIE_INTR2_CPU_BASE		0x4300 +#define PCIE_MSI_INTR2_BASE		0x4500 +/* Offsets from PCIE_INTR2_CPU_BASE and PCIE_MSI_INTR2_BASE */ +#define  MSI_INT_STATUS			0x0 +#define  MSI_INT_CLR			0x8 +#define  MSI_INT_MASK_SET		0x10 +#define  MSI_INT_MASK_CLR		0x14  #define PCIE_EXT_CFG_DATA				0x8000 @@ -120,13 +133,19 @@  #define  PCIE_EXT_SLOT_SHIFT				15  #define  PCIE_EXT_FUNC_SHIFT				12 -#define PCIE_RGR1_SW_INIT_1				0x9210  #define  PCIE_RGR1_SW_INIT_1_PERST_MASK			0x1 -#define  PCIE_RGR1_SW_INIT_1_INIT_MASK			0x2 +#define  PCIE_RGR1_SW_INIT_1_PERST_SHIFT		0x0 + +#define RGR1_SW_INIT_1_INIT_GENERIC_MASK		0x2 +#define RGR1_SW_INIT_1_INIT_GENERIC_SHIFT		0x1 +#define RGR1_SW_INIT_1_INIT_7278_MASK			0x1 +#define RGR1_SW_INIT_1_INIT_7278_SHIFT			0x0  /* PCIe parameters */  #define BRCM_NUM_PCIE_OUT_WINS		0x4  #define BRCM_INT_PCI_MSI_NR		32 +#define BRCM_INT_PCI_MSI_LEGACY_NR	8 +#define BRCM_INT_PCI_MSI_SHIFT		0  /* MSI target adresses */  #define BRCM_MSI_TARGET_ADDR_LT_4GB	0x0fffffffcULL @@ -151,6 +170,85 @@  #define SSC_STATUS_OFFSET		0x1  #define SSC_STATUS_SSC_MASK		0x400  #define SSC_STATUS_PLL_LOCK_MASK	0x800 +#define PCIE_BRCM_MAX_MEMC		3 + +#define IDX_ADDR(pcie)			(pcie->reg_offsets[EXT_CFG_INDEX]) +#define DATA_ADDR(pcie)			(pcie->reg_offsets[EXT_CFG_DATA]) +#define PCIE_RGR1_SW_INIT_1(pcie)	(pcie->reg_offsets[RGR1_SW_INIT_1]) + +/* Rescal registers */ +#define PCIE_DVT_PMU_PCIE_PHY_CTRL				0xc700 +#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS			0x3 +#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_MASK		0x4 +#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_SHIFT	0x2 +#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_MASK		0x2 +#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_SHIFT		0x1 +#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_MASK		0x1 +#define  PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_SHIFT		0x0 + +/* Forward declarations */ +struct brcm_pcie; +static inline void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val); +static inline void brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, u32 val); +static inline void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val); +static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val); + +enum { +	RGR1_SW_INIT_1, +	EXT_CFG_INDEX, +	EXT_CFG_DATA, +}; + +enum { +	RGR1_SW_INIT_1_INIT_MASK, +	RGR1_SW_INIT_1_INIT_SHIFT, +}; + +enum pcie_type { +	GENERIC, +	BCM7278, +	BCM2711, +}; + +struct pcie_cfg_data { +	const int *offsets; +	const enum pcie_type type; +	void (*perst_set)(struct brcm_pcie *pcie, u32 val); +	void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val); +}; + +static const int pcie_offsets[] = { +	[RGR1_SW_INIT_1] = 0x9210, +	[EXT_CFG_INDEX]  = 0x9000, +	[EXT_CFG_DATA]   = 0x9004, +}; + +static const struct pcie_cfg_data generic_cfg = { +	.offsets	= pcie_offsets, +	.type		= GENERIC, +	.perst_set	= brcm_pcie_perst_set_generic, +	.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, +}; + +static const int pcie_offset_bcm7278[] = { +	[RGR1_SW_INIT_1] = 0xc010, +	[EXT_CFG_INDEX] = 0x9000, +	[EXT_CFG_DATA] = 0x9004, +}; + +static const struct pcie_cfg_data bcm7278_cfg = { +	.offsets	= pcie_offset_bcm7278, +	.type		= BCM7278, +	.perst_set	= brcm_pcie_perst_set_7278, +	.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_7278, +}; + +static const struct pcie_cfg_data bcm2711_cfg = { +	.offsets	= pcie_offsets, +	.type		= BCM2711, +	.perst_set	= brcm_pcie_perst_set_generic, +	.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic, +};  struct brcm_msi {  	struct device		*dev; @@ -163,6 +261,12 @@ struct brcm_msi {  	int			irq;  	/* used indicates which MSI interrupts have been alloc'd */  	unsigned long		used; +	bool			legacy; +	/* Some chips have MSIs in bits [31..24] of a shared register. */ +	int			legacy_shift; +	int			nr; /* No. of MSI available, depends on chip */ +	/* This is the base pointer for interrupt status/set/clr regs */ +	void __iomem		*intr_base;  };  /* Internal PCIe Host Controller Information.*/ @@ -175,6 +279,14 @@ struct brcm_pcie {  	int			gen;  	u64			msi_target_addr;  	struct brcm_msi		*msi; +	const int		*reg_offsets; +	enum pcie_type		type; +	struct reset_control	*rescal; +	int			num_memc; +	u64			memc_size[PCIE_BRCM_MAX_MEMC]; +	u32			hw_rev; +	void			(*perst_set)(struct brcm_pcie *pcie, u32 val); +	void			(*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);  };  /* @@ -365,8 +477,10 @@ static void brcm_pcie_msi_isr(struct irq_desc *desc)  	msi = irq_desc_get_handler_data(desc);  	dev = msi->dev; -	status = readl(msi->base + PCIE_MSI_INTR2_STATUS); -	for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) { +	status = readl(msi->intr_base + MSI_INT_STATUS); +	status >>= msi->legacy_shift; + +	for_each_set_bit(bit, &status, msi->nr) {  		virq = irq_find_mapping(msi->inner_domain, bit);  		if (virq)  			generic_handle_irq(virq); @@ -383,7 +497,7 @@ static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)  	msg->address_lo = lower_32_bits(msi->target_addr);  	msg->address_hi = upper_32_bits(msi->target_addr); -	msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL) | data->hwirq; +	msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | data->hwirq;  }  static int brcm_msi_set_affinity(struct irq_data *irq_data, @@ -395,8 +509,9 @@ static int brcm_msi_set_affinity(struct irq_data *irq_data,  static void brcm_msi_ack_irq(struct irq_data *data)  {  	struct brcm_msi *msi = irq_data_get_irq_chip_data(data); +	const int shift_amt = data->hwirq + msi->legacy_shift; -	writel(1 << data->hwirq, msi->base + PCIE_MSI_INTR2_CLR); +	writel(1 << shift_amt, msi->intr_base + MSI_INT_CLR);  } @@ -412,7 +527,7 @@ static int brcm_msi_alloc(struct brcm_msi *msi)  	int hwirq;  	mutex_lock(&msi->lock); -	hwirq = bitmap_find_free_region(&msi->used, BRCM_INT_PCI_MSI_NR, 0); +	hwirq = bitmap_find_free_region(&msi->used, msi->nr, 0);  	mutex_unlock(&msi->lock);  	return hwirq; @@ -461,8 +576,7 @@ static int brcm_allocate_domains(struct brcm_msi *msi)  	struct fwnode_handle *fwnode = of_node_to_fwnode(msi->np);  	struct device *dev = msi->dev; -	msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR, -						  &msi_domain_ops, msi); +	msi->inner_domain = irq_domain_add_linear(NULL, msi->nr, &msi_domain_ops, msi);  	if (!msi->inner_domain) {  		dev_err(dev, "failed to create IRQ domain\n");  		return -ENOMEM; @@ -499,7 +613,10 @@ static void brcm_msi_remove(struct brcm_pcie *pcie)  static void brcm_msi_set_regs(struct brcm_msi *msi)  { -	writel(0xffffffff, msi->base + PCIE_MSI_INTR2_MASK_CLR); +	u32 val = __GENMASK(31, msi->legacy_shift); + +	writel(val, msi->intr_base + MSI_INT_MASK_CLR); +	writel(val, msi->intr_base + MSI_INT_CLR);  	/*  	 * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI @@ -510,8 +627,8 @@ static void brcm_msi_set_regs(struct brcm_msi *msi)  	writel(upper_32_bits(msi->target_addr),  	       msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI); -	writel(PCIE_MISC_MSI_DATA_CONFIG_VAL, -	       msi->base + PCIE_MISC_MSI_DATA_CONFIG); +	val = msi->legacy ? PCIE_MISC_MSI_DATA_CONFIG_VAL_8 : PCIE_MISC_MSI_DATA_CONFIG_VAL_32; +	writel(val, msi->base + PCIE_MISC_MSI_DATA_CONFIG);  }  static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) @@ -536,6 +653,17 @@ static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)  	msi->np = pcie->np;  	msi->target_addr = pcie->msi_target_addr;  	msi->irq = irq; +	msi->legacy = pcie->hw_rev < BRCM_PCIE_HW_REV_33; + +	if (msi->legacy) { +		msi->intr_base = msi->base + PCIE_INTR2_CPU_BASE; +		msi->nr = BRCM_INT_PCI_MSI_LEGACY_NR; +		msi->legacy_shift = 24; +	} else { +		msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE; +		msi->nr = BRCM_INT_PCI_MSI_NR; +		msi->legacy_shift = 0; +	}  	ret = brcm_allocate_domains(msi);  	if (ret) @@ -599,22 +727,43 @@ static struct pci_ops brcm_pcie_ops = {  	.write = pci_generic_config_write,  }; -static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val) +static inline void brcm_pcie_bridge_sw_init_set_generic(struct brcm_pcie *pcie, u32 val) +{ +	u32 tmp, mask =  RGR1_SW_INIT_1_INIT_GENERIC_MASK; +	u32 shift = RGR1_SW_INIT_1_INIT_GENERIC_SHIFT; + +	tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); +	tmp = (tmp & ~mask) | ((val << shift) & mask); +	writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); +} + +static inline void brcm_pcie_bridge_sw_init_set_7278(struct brcm_pcie *pcie, u32 val) +{ +	u32 tmp, mask =  RGR1_SW_INIT_1_INIT_7278_MASK; +	u32 shift = RGR1_SW_INIT_1_INIT_7278_SHIFT; + +	tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); +	tmp = (tmp & ~mask) | ((val << shift) & mask); +	writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie)); +} + +static inline void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val)  {  	u32 tmp; -	tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1); -	u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_INIT_MASK); -	writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1); +	/* Perst bit has moved and assert value is 0 */ +	tmp = readl(pcie->base + PCIE_MISC_PCIE_CTRL); +	u32p_replace_bits(&tmp, !val, PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK); +	writel(tmp, pcie->base +  PCIE_MISC_PCIE_CTRL);  } -static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie, u32 val) +static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val)  {  	u32 tmp; -	tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1); +	tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1(pcie));  	u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_PERST_MASK); -	writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1); +	writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie));  }  static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, @@ -622,22 +771,44 @@ static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie,  							u64 *rc_bar2_offset)  {  	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); -	struct device *dev = pcie->dev;  	struct resource_entry *entry; +	struct device *dev = pcie->dev; +	u64 lowest_pcie_addr = ~(u64)0; +	int ret, i = 0; +	u64 size = 0; -	entry = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM); -	if (!entry) -		return -ENODEV; +	resource_list_for_each_entry(entry, &bridge->dma_ranges) { +		u64 pcie_beg = entry->res->start - entry->offset; +		size += entry->res->end - entry->res->start + 1; +		if (pcie_beg < lowest_pcie_addr) +			lowest_pcie_addr = pcie_beg; +	} -	/* -	 * The controller expects the inbound window offset to be calculated as -	 * the difference between PCIe's address space and CPU's. The offset -	 * provided by the firmware is calculated the opposite way, so we -	 * negate it. -	 */ -	*rc_bar2_offset = -entry->offset; -	*rc_bar2_size = 1ULL << fls64(entry->res->end - entry->res->start); +	if (lowest_pcie_addr == ~(u64)0) { +		dev_err(dev, "DT node has no dma-ranges\n"); +		return -EINVAL; +	} + +	ret = of_property_read_variable_u64_array(pcie->np, "brcm,scb-sizes", pcie->memc_size, 1, +						  PCIE_BRCM_MAX_MEMC); + +	if (ret <= 0) { +		/* Make an educated guess */ +		pcie->num_memc = 1; +		pcie->memc_size[0] = 1ULL << fls64(size - 1); +	} else { +		pcie->num_memc = ret; +	} + +	/* Each memc is viewed through a "port" that is a power of 2 */ +	for (i = 0, size = 0; i < pcie->num_memc; i++) +		size += pcie->memc_size[i]; + +	/* System memory starts at this address in PCIe-space */ +	*rc_bar2_offset = lowest_pcie_addr; +	/* The sum of all memc views must also be a power of 2 */ +	*rc_bar2_size = 1ULL << fls64(size - 1);  	/*  	 * We validate the inbound memory view even though we should trust @@ -689,22 +860,19 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)  	void __iomem *base = pcie->base;  	struct device *dev = pcie->dev;  	struct resource_entry *entry; -	unsigned int scb_size_val;  	bool ssc_good = false;  	struct resource *res;  	int num_out_wins = 0;  	u16 nlw, cls, lnksta; -	int i, ret; -	u32 tmp, aspm_support; +	int i, ret, memc; +	u32 tmp, burst, aspm_support;  	/* Reset the bridge */ -	brcm_pcie_bridge_sw_init_set(pcie, 1); -	brcm_pcie_perst_set(pcie, 1); - +	pcie->bridge_sw_init_set(pcie, 1);  	usleep_range(100, 200);  	/* Take the bridge out of reset */ -	brcm_pcie_bridge_sw_init_set(pcie, 0); +	pcie->bridge_sw_init_set(pcie, 0);  	tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);  	tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK; @@ -712,11 +880,22 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)  	/* Wait for SerDes to be stable */  	usleep_range(100, 200); +	/* +	 * SCB_MAX_BURST_SIZE is a two bit field.  For GENERIC chips it +	 * is encoded as 0=128, 1=256, 2=512, 3=Rsvd, for BCM7278 it +	 * is encoded as 0=Rsvd, 1=128, 2=256, 3=512. +	 */ +	if (pcie->type == BCM2711) +		burst = 0x0; /* 128B */ +	else if (pcie->type == BCM7278) +		burst = 0x3; /* 512 bytes */ +	else +		burst = 0x2; /* 512 bytes */ +  	/* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */  	u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK);  	u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK); -	u32p_replace_bits(&tmp, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128, -			  PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK); +	u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK);  	writel(tmp, base + PCIE_MISC_MISC_CTRL);  	ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size, @@ -731,11 +910,17 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)  	writel(upper_32_bits(rc_bar2_offset),  	       base + PCIE_MISC_RC_BAR2_CONFIG_HI); -	scb_size_val = rc_bar2_size ? -		       ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */  	tmp = readl(base + PCIE_MISC_MISC_CTRL); -	u32p_replace_bits(&tmp, scb_size_val, -			  PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK); +	for (memc = 0; memc < pcie->num_memc; memc++) { +		u32 scb_size_val = ilog2(pcie->memc_size[memc]) - 15; + +		if (memc == 0) +			u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(0)); +		else if (memc == 1) +			u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(1)); +		else if (memc == 2) +			u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(2)); +	}  	writel(tmp, base + PCIE_MISC_MISC_CTRL);  	/* @@ -760,17 +945,11 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)  	tmp &= ~PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK;  	writel(tmp, base + PCIE_MISC_RC_BAR3_CONFIG_LO); -	/* Mask all interrupts since we are not handling any yet */ -	writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_MASK_SET); - -	/* clear any interrupts we find on boot */ -	writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_CLR); -  	if (pcie->gen)  		brcm_pcie_set_gen(pcie, pcie->gen);  	/* Unassert the fundamental reset */ -	brcm_pcie_perst_set(pcie, 0); +	pcie->perst_set(pcie, 0);  	/*  	 * Give the RC/EP time to wake up, before trying to configure RC. @@ -882,6 +1061,52 @@ static void brcm_pcie_enter_l23(struct brcm_pcie *pcie)  		dev_err(pcie->dev, "failed to enter low-power link state\n");  } +static int brcm_phy_cntl(struct brcm_pcie *pcie, const int start) +{ +	static const u32 shifts[PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS] = { +		PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_SHIFT, +		PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_SHIFT, +		PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_SHIFT,}; +	static const u32 masks[PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS] = { +		PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_MASK, +		PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_MASK, +		PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_DIG_RESET_MASK,}; +	const int beg = start ? 0 : PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS - 1; +	const int end = start ? PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS : -1; +	u32 tmp, combined_mask = 0; +	u32 val; +	void __iomem *base = pcie->base; +	int i, ret; + +	for (i = beg; i != end; start ? i++ : i--) { +		val = start ? BIT_MASK(shifts[i]) : 0; +		tmp = readl(base + PCIE_DVT_PMU_PCIE_PHY_CTRL); +		tmp = (tmp & ~masks[i]) | (val & masks[i]); +		writel(tmp, base + PCIE_DVT_PMU_PCIE_PHY_CTRL); +		usleep_range(50, 200); +		combined_mask |= masks[i]; +	} + +	tmp = readl(base + PCIE_DVT_PMU_PCIE_PHY_CTRL); +	val = start ? combined_mask : 0; + +	ret = (tmp & combined_mask) == val ? 0 : -EIO; +	if (ret) +		dev_err(pcie->dev, "failed to %s phy\n", (start ? "start" : "stop")); + +	return ret; +} + +static inline int brcm_phy_start(struct brcm_pcie *pcie) +{ +	return pcie->rescal ? brcm_phy_cntl(pcie, 1) : 0; +} + +static inline int brcm_phy_stop(struct brcm_pcie *pcie) +{ +	return pcie->rescal ? brcm_phy_cntl(pcie, 0) : 0; +} +  static void brcm_pcie_turn_off(struct brcm_pcie *pcie)  {  	void __iomem *base = pcie->base; @@ -890,7 +1115,7 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie)  	if (brcm_pcie_link_up(pcie))  		brcm_pcie_enter_l23(pcie);  	/* Assert fundamental reset */ -	brcm_pcie_perst_set(pcie, 1); +	pcie->perst_set(pcie, 1);  	/* Deassert request for L23 in case it was asserted */  	tmp = readl(base + PCIE_MISC_PCIE_CTRL); @@ -903,13 +1128,66 @@ static void brcm_pcie_turn_off(struct brcm_pcie *pcie)  	writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);  	/* Shutdown PCIe bridge */ -	brcm_pcie_bridge_sw_init_set(pcie, 1); +	pcie->bridge_sw_init_set(pcie, 1); +} + +static int brcm_pcie_suspend(struct device *dev) +{ +	struct brcm_pcie *pcie = dev_get_drvdata(dev); +	int ret; + +	brcm_pcie_turn_off(pcie); +	ret = brcm_phy_stop(pcie); +	clk_disable_unprepare(pcie->clk); + +	return ret; +} + +static int brcm_pcie_resume(struct device *dev) +{ +	struct brcm_pcie *pcie = dev_get_drvdata(dev); +	void __iomem *base; +	u32 tmp; +	int ret; + +	base = pcie->base; +	clk_prepare_enable(pcie->clk); + +	ret = brcm_phy_start(pcie); +	if (ret) +		goto err; + +	/* Take bridge out of reset so we can access the SERDES reg */ +	pcie->bridge_sw_init_set(pcie, 0); + +	/* SERDES_IDDQ = 0 */ +	tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); +	u32p_replace_bits(&tmp, 0, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); +	writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); + +	/* wait for serdes to be stable */ +	udelay(100); + +	ret = brcm_pcie_setup(pcie); +	if (ret) +		goto err; + +	if (pcie->msi) +		brcm_msi_set_regs(pcie->msi); + +	return 0; + +err: +	clk_disable_unprepare(pcie->clk); +	return ret;  }  static void __brcm_pcie_remove(struct brcm_pcie *pcie)  {  	brcm_msi_remove(pcie);  	brcm_pcie_turn_off(pcie); +	brcm_phy_stop(pcie); +	reset_control_assert(pcie->rescal);  	clk_disable_unprepare(pcie->clk);  } @@ -925,10 +1203,20 @@ static int brcm_pcie_remove(struct platform_device *pdev)  	return 0;  } +static const struct of_device_id brcm_pcie_match[] = { +	{ .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg }, +	{ .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg }, +	{ .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg }, +	{ .compatible = "brcm,bcm7216-pcie", .data = &bcm7278_cfg }, +	{ .compatible = "brcm,bcm7445-pcie", .data = &generic_cfg }, +	{}, +}; +  static int brcm_pcie_probe(struct platform_device *pdev)  {  	struct device_node *np = pdev->dev.of_node, *msi_np;  	struct pci_host_bridge *bridge; +	const struct pcie_cfg_data *data;  	struct brcm_pcie *pcie;  	int ret; @@ -936,9 +1224,19 @@ static int brcm_pcie_probe(struct platform_device *pdev)  	if (!bridge)  		return -ENOMEM; +	data = of_device_get_match_data(&pdev->dev); +	if (!data) { +		pr_err("failed to look up compatible string\n"); +		return -EINVAL; +	} +  	pcie = pci_host_bridge_priv(bridge);  	pcie->dev = &pdev->dev;  	pcie->np = np; +	pcie->reg_offsets = data->offsets; +	pcie->type = data->type; +	pcie->perst_set = data->perst_set; +	pcie->bridge_sw_init_set = data->bridge_sw_init_set;  	pcie->base = devm_platform_ioremap_resource(pdev, 0);  	if (IS_ERR(pcie->base)) @@ -958,11 +1256,29 @@ static int brcm_pcie_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "could not enable clock\n");  		return ret;  	} +	pcie->rescal = devm_reset_control_get_optional_shared(&pdev->dev, "rescal"); +	if (IS_ERR(pcie->rescal)) { +		clk_disable_unprepare(pcie->clk); +		return PTR_ERR(pcie->rescal); +	} + +	ret = reset_control_deassert(pcie->rescal); +	if (ret) +		dev_err(&pdev->dev, "failed to deassert 'rescal'\n"); + +	ret = brcm_phy_start(pcie); +	if (ret) { +		reset_control_assert(pcie->rescal); +		clk_disable_unprepare(pcie->clk); +		return ret; +	}  	ret = brcm_pcie_setup(pcie);  	if (ret)  		goto fail; +	pcie->hw_rev = readl(pcie->base + PCIE_MISC_REVISION); +  	msi_np = of_parse_phandle(pcie->np, "msi-parent", 0);  	if (pci_msi_enabled() && msi_np == pcie->np) {  		ret = brcm_pcie_enable_msi(pcie); @@ -983,18 +1299,20 @@ fail:  	return ret;  } -static const struct of_device_id brcm_pcie_match[] = { -	{ .compatible = "brcm,bcm2711-pcie" }, -	{}, -};  MODULE_DEVICE_TABLE(of, brcm_pcie_match); +static const struct dev_pm_ops brcm_pcie_pm_ops = { +	.suspend = brcm_pcie_suspend, +	.resume = brcm_pcie_resume, +}; +  static struct platform_driver brcm_pcie_driver = {  	.probe = brcm_pcie_probe,  	.remove = brcm_pcie_remove,  	.driver = {  		.name = "brcm-pcie",  		.of_match_table = brcm_pcie_match, +		.pm = &brcm_pcie_pm_ops,  	},  };  module_platform_driver(brcm_pcie_driver);  | 
