drivers/pci/controller/dwc/pcie-nxp-s32g.c

Source file repositories/reference/linux-study-clean/drivers/pci/controller/dwc/pcie-nxp-s32g.c

File Facts

System
Linux kernel
Corpus path
drivers/pci/controller/dwc/pcie-nxp-s32g.c
Extension
.c
Size
10023 bytes
Lines
407
Domain
Representative Device Path
Bucket
PCIe NVMe Storage Path
Inferred role
Representative Device Path: implementation source
Status
source implementation candidate

Why This File Exists

Part of the selected hardware vertical slice: PCI discovery, driver binding, NVMe queues, block requests, DMA, interrupts, and completion.

Dependency Surface

Detected Declarations

Annotated Snippet

struct s32g_pcie_port {
	struct list_head list;
	struct phy *phy;
};

struct s32g_pcie {
	struct dw_pcie	pci;
	void __iomem *ctrl_base;
	struct list_head ports;
};

#define to_s32g_from_dw_pcie(x) \
	container_of(x, struct s32g_pcie, pci)

static void s32g_pcie_writel_ctrl(struct s32g_pcie *s32g_pp, u32 reg, u32 val)
{
	writel(val, s32g_pp->ctrl_base + reg);
}

static u32 s32g_pcie_readl_ctrl(struct s32g_pcie *s32g_pp, u32 reg)
{
	return readl(s32g_pp->ctrl_base + reg);
}

static void s32g_pcie_enable_ltssm(struct s32g_pcie *s32g_pp)
{
	u32 reg;

	reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3);
	reg |= LTSSM_EN;
	s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3, reg);
}

static void s32g_pcie_disable_ltssm(struct s32g_pcie *s32g_pp)
{
	u32 reg;

	reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3);
	reg &= ~LTSSM_EN;
	s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3, reg);
}

static int s32g_pcie_start_link(struct dw_pcie *pci)
{
	struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);

	s32g_pcie_enable_ltssm(s32g_pp);

	return 0;
}

static void s32g_pcie_stop_link(struct dw_pcie *pci)
{
	struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);

	s32g_pcie_disable_ltssm(s32g_pp);
}

static struct dw_pcie_ops s32g_pcie_ops = {
	.start_link = s32g_pcie_start_link,
	.stop_link = s32g_pcie_stop_link,
};

/* Configure the AMBA AXI Coherency Extensions (ACE) interface */
static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci)
{
	u32 ddr_base_low = lower_32_bits(S32G_MEMORY_BOUNDARY_ADDR);
	u32 ddr_base_high = upper_32_bits(S32G_MEMORY_BOUNDARY_ADDR);

	dw_pcie_dbi_ro_wr_en(pci);
	dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, 0x0);

	/*
	 * Ncore is a cache-coherent interconnect module that enables the
	 * integration of heterogeneous coherent and non-coherent agents in
	 * the chip. Ncore transactions to peripheral should be non-coherent
	 * or it might drop them.
	 *
	 * One example where this is needed are PCIe MSIs, which use NoSnoop=0
	 * and might end up routed to Ncore. PCIe coherent traffic (e.g. MSIs)
	 * that targets peripheral space will be dropped by Ncore because
	 * peripherals on S32G are not coherent as slaves. We add a hard
	 * boundary in the PCIe controller coherency control registers to
	 * separate physical memory space from peripheral space.
	 *
	 * Define the start of DDR as seen by Linux as this boundary between
	 * "memory" and "peripherals", with peripherals being below.
	 */
	dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_1_OFF,
			   (ddr_base_low & CFG_MEMTYPE_BOUNDARY_LOW_ADDR_MASK));

Annotation

Implementation Notes