18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Rockchip AXI PCIe endpoint controller driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2018 Rockchip, Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Shawn Lin <shawn.lin@rock-chips.com>
88c2ecf20Sopenharmony_ci *         Simon Xue <xxm@rock-chips.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/configfs.h>
128c2ecf20Sopenharmony_ci#include <linux/delay.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/of.h>
158c2ecf20Sopenharmony_ci#include <linux/pci-epc.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
178c2ecf20Sopenharmony_ci#include <linux/pci-epf.h>
188c2ecf20Sopenharmony_ci#include <linux/sizes.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "pcie-rockchip.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/**
238c2ecf20Sopenharmony_ci * struct rockchip_pcie_ep - private data for PCIe endpoint controller driver
248c2ecf20Sopenharmony_ci * @rockchip: Rockchip PCIe controller
258c2ecf20Sopenharmony_ci * @epc: PCI EPC device
268c2ecf20Sopenharmony_ci * @max_regions: maximum number of regions supported by hardware
278c2ecf20Sopenharmony_ci * @ob_region_map: bitmask of mapped outbound regions
288c2ecf20Sopenharmony_ci * @ob_addr: base addresses in the AXI bus where the outbound regions start
298c2ecf20Sopenharmony_ci * @irq_phys_addr: base address on the AXI bus where the MSI/legacy IRQ
308c2ecf20Sopenharmony_ci *		   dedicated outbound regions is mapped.
318c2ecf20Sopenharmony_ci * @irq_cpu_addr: base address in the CPU space where a write access triggers
328c2ecf20Sopenharmony_ci *		  the sending of a memory write (MSI) / normal message (legacy
338c2ecf20Sopenharmony_ci *		  IRQ) TLP through the PCIe bus.
348c2ecf20Sopenharmony_ci * @irq_pci_addr: used to save the current mapping of the MSI/legacy IRQ
358c2ecf20Sopenharmony_ci *		  dedicated outbound region.
368c2ecf20Sopenharmony_ci * @irq_pci_fn: the latest PCI function that has updated the mapping of
378c2ecf20Sopenharmony_ci *		the MSI/legacy IRQ dedicated outbound region.
388c2ecf20Sopenharmony_ci * @irq_pending: bitmask of asserted legacy IRQs.
398c2ecf20Sopenharmony_ci */
408c2ecf20Sopenharmony_cistruct rockchip_pcie_ep {
418c2ecf20Sopenharmony_ci	struct rockchip_pcie	rockchip;
428c2ecf20Sopenharmony_ci	struct pci_epc		*epc;
438c2ecf20Sopenharmony_ci	u32			max_regions;
448c2ecf20Sopenharmony_ci	unsigned long		ob_region_map;
458c2ecf20Sopenharmony_ci	phys_addr_t		*ob_addr;
468c2ecf20Sopenharmony_ci	phys_addr_t		irq_phys_addr;
478c2ecf20Sopenharmony_ci	void __iomem		*irq_cpu_addr;
488c2ecf20Sopenharmony_ci	u64			irq_pci_addr;
498c2ecf20Sopenharmony_ci	u8			irq_pci_fn;
508c2ecf20Sopenharmony_ci	u8			irq_pending;
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic void rockchip_pcie_clear_ep_ob_atu(struct rockchip_pcie *rockchip,
548c2ecf20Sopenharmony_ci					  u32 region)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, 0,
578c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(region));
588c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, 0,
598c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(region));
608c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, 0,
618c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_AT_OB_REGION_DESC0(region));
628c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, 0,
638c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_AT_OB_REGION_DESC1(region));
648c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, 0,
658c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR0(region));
668c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, 0,
678c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR1(region));
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rockchip, u8 fn,
718c2ecf20Sopenharmony_ci					 u32 r, u32 type, u64 cpu_addr,
728c2ecf20Sopenharmony_ci					 u64 pci_addr, size_t size)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	u64 sz = 1ULL << fls64(size - 1);
758c2ecf20Sopenharmony_ci	int num_pass_bits = ilog2(sz);
768c2ecf20Sopenharmony_ci	u32 addr0, addr1, desc0, desc1;
778c2ecf20Sopenharmony_ci	bool is_nor_msg = (type == AXI_WRAPPER_NOR_MSG);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	/* The minimal region size is 1MB */
808c2ecf20Sopenharmony_ci	if (num_pass_bits < 8)
818c2ecf20Sopenharmony_ci		num_pass_bits = 8;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	cpu_addr -= rockchip->mem_res->start;
848c2ecf20Sopenharmony_ci	addr0 = ((is_nor_msg ? 0x10 : (num_pass_bits - 1)) &
858c2ecf20Sopenharmony_ci		PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) |
868c2ecf20Sopenharmony_ci		(lower_32_bits(cpu_addr) & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
878c2ecf20Sopenharmony_ci	addr1 = upper_32_bits(is_nor_msg ? cpu_addr : pci_addr);
888c2ecf20Sopenharmony_ci	desc0 = ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(fn) | type;
898c2ecf20Sopenharmony_ci	desc1 = 0;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (is_nor_msg) {
928c2ecf20Sopenharmony_ci		rockchip_pcie_write(rockchip, 0,
938c2ecf20Sopenharmony_ci				    ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r));
948c2ecf20Sopenharmony_ci		rockchip_pcie_write(rockchip, 0,
958c2ecf20Sopenharmony_ci				    ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r));
968c2ecf20Sopenharmony_ci		rockchip_pcie_write(rockchip, desc0,
978c2ecf20Sopenharmony_ci				    ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r));
988c2ecf20Sopenharmony_ci		rockchip_pcie_write(rockchip, desc1,
998c2ecf20Sopenharmony_ci				    ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r));
1008c2ecf20Sopenharmony_ci	} else {
1018c2ecf20Sopenharmony_ci		/* PCI bus address region */
1028c2ecf20Sopenharmony_ci		rockchip_pcie_write(rockchip, addr0,
1038c2ecf20Sopenharmony_ci				    ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r));
1048c2ecf20Sopenharmony_ci		rockchip_pcie_write(rockchip, addr1,
1058c2ecf20Sopenharmony_ci				    ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r));
1068c2ecf20Sopenharmony_ci		rockchip_pcie_write(rockchip, desc0,
1078c2ecf20Sopenharmony_ci				    ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r));
1088c2ecf20Sopenharmony_ci		rockchip_pcie_write(rockchip, desc1,
1098c2ecf20Sopenharmony_ci				    ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r));
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci		addr0 =
1128c2ecf20Sopenharmony_ci		    ((num_pass_bits - 1) & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) |
1138c2ecf20Sopenharmony_ci		    (lower_32_bits(cpu_addr) &
1148c2ecf20Sopenharmony_ci		     PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
1158c2ecf20Sopenharmony_ci		addr1 = upper_32_bits(cpu_addr);
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/* CPU bus address region */
1198c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, addr0,
1208c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR0(r));
1218c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, addr1,
1228c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR1(r));
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int rockchip_pcie_ep_write_header(struct pci_epc *epc, u8 fn,
1268c2ecf20Sopenharmony_ci					 struct pci_epf_header *hdr)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	u32 reg;
1298c2ecf20Sopenharmony_ci	struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
1308c2ecf20Sopenharmony_ci	struct rockchip_pcie *rockchip = &ep->rockchip;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	/* All functions share the same vendor ID with function 0 */
1338c2ecf20Sopenharmony_ci	if (fn == 0) {
1348c2ecf20Sopenharmony_ci		u32 vid_regs = (hdr->vendorid & GENMASK(15, 0)) |
1358c2ecf20Sopenharmony_ci			       (hdr->subsys_vendor_id & GENMASK(31, 16)) << 16;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci		rockchip_pcie_write(rockchip, vid_regs,
1388c2ecf20Sopenharmony_ci				    PCIE_CORE_CONFIG_VENDOR);
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	reg = rockchip_pcie_read(rockchip, PCIE_EP_CONFIG_DID_VID);
1428c2ecf20Sopenharmony_ci	reg = (reg & 0xFFFF) | (hdr->deviceid << 16);
1438c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, reg, PCIE_EP_CONFIG_DID_VID);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip,
1468c2ecf20Sopenharmony_ci			    hdr->revid |
1478c2ecf20Sopenharmony_ci			    hdr->progif_code << 8 |
1488c2ecf20Sopenharmony_ci			    hdr->subclass_code << 16 |
1498c2ecf20Sopenharmony_ci			    hdr->baseclass_code << 24,
1508c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_EP_FUNC_BASE(fn) + PCI_REVISION_ID);
1518c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, hdr->cache_line_size,
1528c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
1538c2ecf20Sopenharmony_ci			    PCI_CACHE_LINE_SIZE);
1548c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, hdr->subsys_id << 16,
1558c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
1568c2ecf20Sopenharmony_ci			    PCI_SUBSYSTEM_VENDOR_ID);
1578c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, hdr->interrupt_pin << 8,
1588c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
1598c2ecf20Sopenharmony_ci			    PCI_INTERRUPT_LINE);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return 0;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic int rockchip_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
1658c2ecf20Sopenharmony_ci				    struct pci_epf_bar *epf_bar)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
1688c2ecf20Sopenharmony_ci	struct rockchip_pcie *rockchip = &ep->rockchip;
1698c2ecf20Sopenharmony_ci	dma_addr_t bar_phys = epf_bar->phys_addr;
1708c2ecf20Sopenharmony_ci	enum pci_barno bar = epf_bar->barno;
1718c2ecf20Sopenharmony_ci	int flags = epf_bar->flags;
1728c2ecf20Sopenharmony_ci	u32 addr0, addr1, reg, cfg, b, aperture, ctrl;
1738c2ecf20Sopenharmony_ci	u64 sz;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	/* BAR size is 2^(aperture + 7) */
1768c2ecf20Sopenharmony_ci	sz = max_t(size_t, epf_bar->size, MIN_EP_APERTURE);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/*
1798c2ecf20Sopenharmony_ci	 * roundup_pow_of_two() returns an unsigned long, which is not suited
1808c2ecf20Sopenharmony_ci	 * for 64bit values.
1818c2ecf20Sopenharmony_ci	 */
1828c2ecf20Sopenharmony_ci	sz = 1ULL << fls64(sz - 1);
1838c2ecf20Sopenharmony_ci	aperture = ilog2(sz) - 7; /* 128B -> 0, 256B -> 1, 512B -> 2, ... */
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
1868c2ecf20Sopenharmony_ci		ctrl = ROCKCHIP_PCIE_CORE_BAR_CFG_CTRL_IO_32BITS;
1878c2ecf20Sopenharmony_ci	} else {
1888c2ecf20Sopenharmony_ci		bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH);
1898c2ecf20Sopenharmony_ci		bool is_64bits = sz > SZ_2G;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		if (is_64bits && (bar & 1))
1928c2ecf20Sopenharmony_ci			return -EINVAL;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		if (is_64bits && is_prefetch)
1958c2ecf20Sopenharmony_ci			ctrl =
1968c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_CORE_BAR_CFG_CTRL_PREFETCH_MEM_64BITS;
1978c2ecf20Sopenharmony_ci		else if (is_prefetch)
1988c2ecf20Sopenharmony_ci			ctrl =
1998c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_CORE_BAR_CFG_CTRL_PREFETCH_MEM_32BITS;
2008c2ecf20Sopenharmony_ci		else if (is_64bits)
2018c2ecf20Sopenharmony_ci			ctrl = ROCKCHIP_PCIE_CORE_BAR_CFG_CTRL_MEM_64BITS;
2028c2ecf20Sopenharmony_ci		else
2038c2ecf20Sopenharmony_ci			ctrl = ROCKCHIP_PCIE_CORE_BAR_CFG_CTRL_MEM_32BITS;
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	if (bar < BAR_4) {
2078c2ecf20Sopenharmony_ci		reg = ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG0(fn);
2088c2ecf20Sopenharmony_ci		b = bar;
2098c2ecf20Sopenharmony_ci	} else {
2108c2ecf20Sopenharmony_ci		reg = ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG1(fn);
2118c2ecf20Sopenharmony_ci		b = bar - BAR_4;
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	addr0 = lower_32_bits(bar_phys);
2158c2ecf20Sopenharmony_ci	addr1 = upper_32_bits(bar_phys);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	cfg = rockchip_pcie_read(rockchip, reg);
2188c2ecf20Sopenharmony_ci	cfg &= ~(ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
2198c2ecf20Sopenharmony_ci		 ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
2208c2ecf20Sopenharmony_ci	cfg |= (ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) |
2218c2ecf20Sopenharmony_ci		ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, cfg, reg);
2248c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, addr0,
2258c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar));
2268c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, addr1,
2278c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar));
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	return 0;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic void rockchip_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
2338c2ecf20Sopenharmony_ci				       struct pci_epf_bar *epf_bar)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
2368c2ecf20Sopenharmony_ci	struct rockchip_pcie *rockchip = &ep->rockchip;
2378c2ecf20Sopenharmony_ci	u32 reg, cfg, b, ctrl;
2388c2ecf20Sopenharmony_ci	enum pci_barno bar = epf_bar->barno;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	if (bar < BAR_4) {
2418c2ecf20Sopenharmony_ci		reg = ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG0(fn);
2428c2ecf20Sopenharmony_ci		b = bar;
2438c2ecf20Sopenharmony_ci	} else {
2448c2ecf20Sopenharmony_ci		reg = ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG1(fn);
2458c2ecf20Sopenharmony_ci		b = bar - BAR_4;
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	ctrl = ROCKCHIP_PCIE_CORE_BAR_CFG_CTRL_DISABLED;
2498c2ecf20Sopenharmony_ci	cfg = rockchip_pcie_read(rockchip, reg);
2508c2ecf20Sopenharmony_ci	cfg &= ~(ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
2518c2ecf20Sopenharmony_ci		 ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
2528c2ecf20Sopenharmony_ci	cfg |= ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, cfg, reg);
2558c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, 0x0,
2568c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar));
2578c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, 0x0,
2588c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar));
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic int rockchip_pcie_ep_map_addr(struct pci_epc *epc, u8 fn,
2628c2ecf20Sopenharmony_ci				     phys_addr_t addr, u64 pci_addr,
2638c2ecf20Sopenharmony_ci				     size_t size)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
2668c2ecf20Sopenharmony_ci	struct rockchip_pcie *pcie = &ep->rockchip;
2678c2ecf20Sopenharmony_ci	u32 r;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	r = find_first_zero_bit(&ep->ob_region_map, BITS_PER_LONG);
2708c2ecf20Sopenharmony_ci	/*
2718c2ecf20Sopenharmony_ci	 * Region 0 is reserved for configuration space and shouldn't
2728c2ecf20Sopenharmony_ci	 * be used elsewhere per TRM, so leave it out.
2738c2ecf20Sopenharmony_ci	 */
2748c2ecf20Sopenharmony_ci	if (r >= ep->max_regions - 1) {
2758c2ecf20Sopenharmony_ci		dev_err(&epc->dev, "no free outbound region\n");
2768c2ecf20Sopenharmony_ci		return -EINVAL;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	rockchip_pcie_prog_ep_ob_atu(pcie, fn, r, AXI_WRAPPER_MEM_WRITE, addr,
2808c2ecf20Sopenharmony_ci				     pci_addr, size);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	set_bit(r, &ep->ob_region_map);
2838c2ecf20Sopenharmony_ci	ep->ob_addr[r] = addr;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	return 0;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic void rockchip_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn,
2898c2ecf20Sopenharmony_ci					phys_addr_t addr)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
2928c2ecf20Sopenharmony_ci	struct rockchip_pcie *rockchip = &ep->rockchip;
2938c2ecf20Sopenharmony_ci	u32 r;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	for (r = 0; r < ep->max_regions - 1; r++)
2968c2ecf20Sopenharmony_ci		if (ep->ob_addr[r] == addr)
2978c2ecf20Sopenharmony_ci			break;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/*
3008c2ecf20Sopenharmony_ci	 * Region 0 is reserved for configuration space and shouldn't
3018c2ecf20Sopenharmony_ci	 * be used elsewhere per TRM, so leave it out.
3028c2ecf20Sopenharmony_ci	 */
3038c2ecf20Sopenharmony_ci	if (r == ep->max_regions - 1)
3048c2ecf20Sopenharmony_ci		return;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	rockchip_pcie_clear_ep_ob_atu(rockchip, r);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	ep->ob_addr[r] = 0;
3098c2ecf20Sopenharmony_ci	clear_bit(r, &ep->ob_region_map);
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic int rockchip_pcie_ep_set_msi(struct pci_epc *epc, u8 fn,
3138c2ecf20Sopenharmony_ci				    u8 multi_msg_cap)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
3168c2ecf20Sopenharmony_ci	struct rockchip_pcie *rockchip = &ep->rockchip;
3178c2ecf20Sopenharmony_ci	u32 flags;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	flags = rockchip_pcie_read(rockchip,
3208c2ecf20Sopenharmony_ci				   ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
3218c2ecf20Sopenharmony_ci				   ROCKCHIP_PCIE_EP_MSI_CTRL_REG);
3228c2ecf20Sopenharmony_ci	flags &= ~ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_MASK;
3238c2ecf20Sopenharmony_ci	flags |=
3248c2ecf20Sopenharmony_ci	   (multi_msg_cap << ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_OFFSET) |
3258c2ecf20Sopenharmony_ci	   (PCI_MSI_FLAGS_64BIT << ROCKCHIP_PCIE_EP_MSI_FLAGS_OFFSET);
3268c2ecf20Sopenharmony_ci	flags &= ~ROCKCHIP_PCIE_EP_MSI_CTRL_MASK_MSI_CAP;
3278c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, flags,
3288c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
3298c2ecf20Sopenharmony_ci			    ROCKCHIP_PCIE_EP_MSI_CTRL_REG);
3308c2ecf20Sopenharmony_ci	return 0;
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic int rockchip_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
3368c2ecf20Sopenharmony_ci	struct rockchip_pcie *rockchip = &ep->rockchip;
3378c2ecf20Sopenharmony_ci	u32 flags;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	flags = rockchip_pcie_read(rockchip,
3408c2ecf20Sopenharmony_ci				   ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
3418c2ecf20Sopenharmony_ci				   ROCKCHIP_PCIE_EP_MSI_CTRL_REG);
3428c2ecf20Sopenharmony_ci	if (!(flags & ROCKCHIP_PCIE_EP_MSI_CTRL_ME))
3438c2ecf20Sopenharmony_ci		return -EINVAL;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	return ((flags & ROCKCHIP_PCIE_EP_MSI_CTRL_MME_MASK) >>
3468c2ecf20Sopenharmony_ci			ROCKCHIP_PCIE_EP_MSI_CTRL_MME_OFFSET);
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic void rockchip_pcie_ep_assert_intx(struct rockchip_pcie_ep *ep, u8 fn,
3508c2ecf20Sopenharmony_ci					 u8 intx, bool do_assert)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	struct rockchip_pcie *rockchip = &ep->rockchip;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	intx &= 3;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (do_assert) {
3578c2ecf20Sopenharmony_ci		ep->irq_pending |= BIT(intx);
3588c2ecf20Sopenharmony_ci		rockchip_pcie_write(rockchip,
3598c2ecf20Sopenharmony_ci				    PCIE_CLIENT_INT_IN_ASSERT |
3608c2ecf20Sopenharmony_ci				    PCIE_CLIENT_INT_PEND_ST_PEND,
3618c2ecf20Sopenharmony_ci				    PCIE_CLIENT_LEGACY_INT_CTRL);
3628c2ecf20Sopenharmony_ci	} else {
3638c2ecf20Sopenharmony_ci		ep->irq_pending &= ~BIT(intx);
3648c2ecf20Sopenharmony_ci		rockchip_pcie_write(rockchip,
3658c2ecf20Sopenharmony_ci				    PCIE_CLIENT_INT_IN_DEASSERT |
3668c2ecf20Sopenharmony_ci				    PCIE_CLIENT_INT_PEND_ST_NORMAL,
3678c2ecf20Sopenharmony_ci				    PCIE_CLIENT_LEGACY_INT_CTRL);
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic int rockchip_pcie_ep_send_legacy_irq(struct rockchip_pcie_ep *ep, u8 fn,
3728c2ecf20Sopenharmony_ci					    u8 intx)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	u16 cmd;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	cmd = rockchip_pcie_read(&ep->rockchip,
3778c2ecf20Sopenharmony_ci				 ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
3788c2ecf20Sopenharmony_ci				 ROCKCHIP_PCIE_EP_CMD_STATUS);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (cmd & PCI_COMMAND_INTX_DISABLE)
3818c2ecf20Sopenharmony_ci		return -EINVAL;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	/*
3848c2ecf20Sopenharmony_ci	 * Should add some delay between toggling INTx per TRM vaguely saying
3858c2ecf20Sopenharmony_ci	 * it depends on some cycles of the AHB bus clock to function it. So
3868c2ecf20Sopenharmony_ci	 * add sufficient 1ms here.
3878c2ecf20Sopenharmony_ci	 */
3888c2ecf20Sopenharmony_ci	rockchip_pcie_ep_assert_intx(ep, fn, intx, true);
3898c2ecf20Sopenharmony_ci	mdelay(1);
3908c2ecf20Sopenharmony_ci	rockchip_pcie_ep_assert_intx(ep, fn, intx, false);
3918c2ecf20Sopenharmony_ci	return 0;
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn,
3958c2ecf20Sopenharmony_ci					 u8 interrupt_num)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	struct rockchip_pcie *rockchip = &ep->rockchip;
3988c2ecf20Sopenharmony_ci	u32 flags, mme, data, data_mask;
3998c2ecf20Sopenharmony_ci	u8 msi_count;
4008c2ecf20Sopenharmony_ci	u64 pci_addr, pci_addr_mask = 0xff;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	/* Check MSI enable bit */
4038c2ecf20Sopenharmony_ci	flags = rockchip_pcie_read(&ep->rockchip,
4048c2ecf20Sopenharmony_ci				   ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
4058c2ecf20Sopenharmony_ci				   ROCKCHIP_PCIE_EP_MSI_CTRL_REG);
4068c2ecf20Sopenharmony_ci	if (!(flags & ROCKCHIP_PCIE_EP_MSI_CTRL_ME))
4078c2ecf20Sopenharmony_ci		return -EINVAL;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* Get MSI numbers from MME */
4108c2ecf20Sopenharmony_ci	mme = ((flags & ROCKCHIP_PCIE_EP_MSI_CTRL_MME_MASK) >>
4118c2ecf20Sopenharmony_ci			ROCKCHIP_PCIE_EP_MSI_CTRL_MME_OFFSET);
4128c2ecf20Sopenharmony_ci	msi_count = 1 << mme;
4138c2ecf20Sopenharmony_ci	if (!interrupt_num || interrupt_num > msi_count)
4148c2ecf20Sopenharmony_ci		return -EINVAL;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	/* Set MSI private data */
4178c2ecf20Sopenharmony_ci	data_mask = msi_count - 1;
4188c2ecf20Sopenharmony_ci	data = rockchip_pcie_read(rockchip,
4198c2ecf20Sopenharmony_ci				  ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
4208c2ecf20Sopenharmony_ci				  ROCKCHIP_PCIE_EP_MSI_CTRL_REG +
4218c2ecf20Sopenharmony_ci				  PCI_MSI_DATA_64);
4228c2ecf20Sopenharmony_ci	data = (data & ~data_mask) | ((interrupt_num - 1) & data_mask);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	/* Get MSI PCI address */
4258c2ecf20Sopenharmony_ci	pci_addr = rockchip_pcie_read(rockchip,
4268c2ecf20Sopenharmony_ci				      ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
4278c2ecf20Sopenharmony_ci				      ROCKCHIP_PCIE_EP_MSI_CTRL_REG +
4288c2ecf20Sopenharmony_ci				      PCI_MSI_ADDRESS_HI);
4298c2ecf20Sopenharmony_ci	pci_addr <<= 32;
4308c2ecf20Sopenharmony_ci	pci_addr |= rockchip_pcie_read(rockchip,
4318c2ecf20Sopenharmony_ci				       ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
4328c2ecf20Sopenharmony_ci				       ROCKCHIP_PCIE_EP_MSI_CTRL_REG +
4338c2ecf20Sopenharmony_ci				       PCI_MSI_ADDRESS_LO);
4348c2ecf20Sopenharmony_ci	pci_addr &= GENMASK_ULL(63, 2);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	/* Set the outbound region if needed. */
4378c2ecf20Sopenharmony_ci	if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) ||
4388c2ecf20Sopenharmony_ci		     ep->irq_pci_fn != fn)) {
4398c2ecf20Sopenharmony_ci		rockchip_pcie_prog_ep_ob_atu(rockchip, fn, ep->max_regions - 1,
4408c2ecf20Sopenharmony_ci					     AXI_WRAPPER_MEM_WRITE,
4418c2ecf20Sopenharmony_ci					     ep->irq_phys_addr,
4428c2ecf20Sopenharmony_ci					     pci_addr & ~pci_addr_mask,
4438c2ecf20Sopenharmony_ci					     pci_addr_mask + 1);
4448c2ecf20Sopenharmony_ci		ep->irq_pci_addr = (pci_addr & ~pci_addr_mask);
4458c2ecf20Sopenharmony_ci		ep->irq_pci_fn = fn;
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	writew(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask));
4498c2ecf20Sopenharmony_ci	return 0;
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic int rockchip_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
4538c2ecf20Sopenharmony_ci				      enum pci_epc_irq_type type,
4548c2ecf20Sopenharmony_ci				      u16 interrupt_num)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	switch (type) {
4598c2ecf20Sopenharmony_ci	case PCI_EPC_IRQ_LEGACY:
4608c2ecf20Sopenharmony_ci		return rockchip_pcie_ep_send_legacy_irq(ep, fn, 0);
4618c2ecf20Sopenharmony_ci	case PCI_EPC_IRQ_MSI:
4628c2ecf20Sopenharmony_ci		return rockchip_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
4638c2ecf20Sopenharmony_ci	default:
4648c2ecf20Sopenharmony_ci		return -EINVAL;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic int rockchip_pcie_ep_start(struct pci_epc *epc)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
4718c2ecf20Sopenharmony_ci	struct rockchip_pcie *rockchip = &ep->rockchip;
4728c2ecf20Sopenharmony_ci	struct pci_epf *epf;
4738c2ecf20Sopenharmony_ci	u32 cfg;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	cfg = BIT(0);
4768c2ecf20Sopenharmony_ci	list_for_each_entry(epf, &epc->pci_epf, list)
4778c2ecf20Sopenharmony_ci		cfg |= BIT(epf->func_no);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, cfg, PCIE_CORE_PHY_FUNC_CFG);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	return 0;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic const struct pci_epc_features rockchip_pcie_epc_features = {
4858c2ecf20Sopenharmony_ci	.linkup_notifier = false,
4868c2ecf20Sopenharmony_ci	.msi_capable = true,
4878c2ecf20Sopenharmony_ci	.msix_capable = false,
4888c2ecf20Sopenharmony_ci	.align = 256,
4898c2ecf20Sopenharmony_ci};
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic const struct pci_epc_features*
4928c2ecf20Sopenharmony_cirockchip_pcie_ep_get_features(struct pci_epc *epc, u8 func_no)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	return &rockchip_pcie_epc_features;
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistatic const struct pci_epc_ops rockchip_pcie_epc_ops = {
4988c2ecf20Sopenharmony_ci	.write_header	= rockchip_pcie_ep_write_header,
4998c2ecf20Sopenharmony_ci	.set_bar	= rockchip_pcie_ep_set_bar,
5008c2ecf20Sopenharmony_ci	.clear_bar	= rockchip_pcie_ep_clear_bar,
5018c2ecf20Sopenharmony_ci	.map_addr	= rockchip_pcie_ep_map_addr,
5028c2ecf20Sopenharmony_ci	.unmap_addr	= rockchip_pcie_ep_unmap_addr,
5038c2ecf20Sopenharmony_ci	.set_msi	= rockchip_pcie_ep_set_msi,
5048c2ecf20Sopenharmony_ci	.get_msi	= rockchip_pcie_ep_get_msi,
5058c2ecf20Sopenharmony_ci	.raise_irq	= rockchip_pcie_ep_raise_irq,
5068c2ecf20Sopenharmony_ci	.start		= rockchip_pcie_ep_start,
5078c2ecf20Sopenharmony_ci	.get_features	= rockchip_pcie_ep_get_features,
5088c2ecf20Sopenharmony_ci};
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int rockchip_pcie_parse_ep_dt(struct rockchip_pcie *rockchip,
5118c2ecf20Sopenharmony_ci				     struct rockchip_pcie_ep *ep)
5128c2ecf20Sopenharmony_ci{
5138c2ecf20Sopenharmony_ci	struct device *dev = rockchip->dev;
5148c2ecf20Sopenharmony_ci	int err;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	err = rockchip_pcie_parse_dt(rockchip);
5178c2ecf20Sopenharmony_ci	if (err)
5188c2ecf20Sopenharmony_ci		return err;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	err = rockchip_pcie_get_phys(rockchip);
5218c2ecf20Sopenharmony_ci	if (err)
5228c2ecf20Sopenharmony_ci		return err;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	err = of_property_read_u32(dev->of_node,
5258c2ecf20Sopenharmony_ci				   "rockchip,max-outbound-regions",
5268c2ecf20Sopenharmony_ci				   &ep->max_regions);
5278c2ecf20Sopenharmony_ci	if (err < 0 || ep->max_regions > MAX_REGION_LIMIT)
5288c2ecf20Sopenharmony_ci		ep->max_regions = MAX_REGION_LIMIT;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	err = of_property_read_u8(dev->of_node, "max-functions",
5318c2ecf20Sopenharmony_ci				  &ep->epc->max_functions);
5328c2ecf20Sopenharmony_ci	if (err < 0)
5338c2ecf20Sopenharmony_ci		ep->epc->max_functions = 1;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	return 0;
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistatic const struct of_device_id rockchip_pcie_ep_of_match[] = {
5398c2ecf20Sopenharmony_ci	{ .compatible = "rockchip,rk3399-pcie-ep"},
5408c2ecf20Sopenharmony_ci	{},
5418c2ecf20Sopenharmony_ci};
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistatic int rockchip_pcie_ep_probe(struct platform_device *pdev)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
5468c2ecf20Sopenharmony_ci	struct rockchip_pcie_ep *ep;
5478c2ecf20Sopenharmony_ci	struct rockchip_pcie *rockchip;
5488c2ecf20Sopenharmony_ci	struct pci_epc *epc;
5498c2ecf20Sopenharmony_ci	size_t max_regions;
5508c2ecf20Sopenharmony_ci	int err;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
5538c2ecf20Sopenharmony_ci	if (!ep)
5548c2ecf20Sopenharmony_ci		return -ENOMEM;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	rockchip = &ep->rockchip;
5578c2ecf20Sopenharmony_ci	rockchip->is_rc = false;
5588c2ecf20Sopenharmony_ci	rockchip->dev = dev;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	epc = devm_pci_epc_create(dev, &rockchip_pcie_epc_ops);
5618c2ecf20Sopenharmony_ci	if (IS_ERR(epc)) {
5628c2ecf20Sopenharmony_ci		dev_err(dev, "failed to create epc device\n");
5638c2ecf20Sopenharmony_ci		return PTR_ERR(epc);
5648c2ecf20Sopenharmony_ci	}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	ep->epc = epc;
5678c2ecf20Sopenharmony_ci	epc_set_drvdata(epc, ep);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	err = rockchip_pcie_parse_ep_dt(rockchip, ep);
5708c2ecf20Sopenharmony_ci	if (err)
5718c2ecf20Sopenharmony_ci		return err;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	err = rockchip_pcie_enable_clocks(rockchip);
5748c2ecf20Sopenharmony_ci	if (err)
5758c2ecf20Sopenharmony_ci		return err;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	err = rockchip_pcie_init_port(rockchip);
5788c2ecf20Sopenharmony_ci	if (err)
5798c2ecf20Sopenharmony_ci		goto err_disable_clocks;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	/* Establish the link automatically */
5828c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, PCIE_CLIENT_LINK_TRAIN_ENABLE,
5838c2ecf20Sopenharmony_ci			    PCIE_CLIENT_CONFIG);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	max_regions = ep->max_regions;
5868c2ecf20Sopenharmony_ci	ep->ob_addr = devm_kcalloc(dev, max_regions, sizeof(*ep->ob_addr),
5878c2ecf20Sopenharmony_ci				   GFP_KERNEL);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	if (!ep->ob_addr) {
5908c2ecf20Sopenharmony_ci		err = -ENOMEM;
5918c2ecf20Sopenharmony_ci		goto err_uninit_port;
5928c2ecf20Sopenharmony_ci	}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	/* Only enable function 0 by default */
5958c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, BIT(0), PCIE_CORE_PHY_FUNC_CFG);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	err = pci_epc_mem_init(epc, rockchip->mem_res->start,
5988c2ecf20Sopenharmony_ci			       resource_size(rockchip->mem_res), PAGE_SIZE);
5998c2ecf20Sopenharmony_ci	if (err < 0) {
6008c2ecf20Sopenharmony_ci		dev_err(dev, "failed to initialize the memory space\n");
6018c2ecf20Sopenharmony_ci		goto err_uninit_port;
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
6058c2ecf20Sopenharmony_ci						  SZ_128K);
6068c2ecf20Sopenharmony_ci	if (!ep->irq_cpu_addr) {
6078c2ecf20Sopenharmony_ci		dev_err(dev, "failed to reserve memory space for MSI\n");
6088c2ecf20Sopenharmony_ci		err = -ENOMEM;
6098c2ecf20Sopenharmony_ci		goto err_epc_mem_exit;
6108c2ecf20Sopenharmony_ci	}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	ep->irq_pci_addr = ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	rockchip_pcie_write(rockchip, PCIE_CLIENT_CONF_ENABLE,
6158c2ecf20Sopenharmony_ci			    PCIE_CLIENT_CONFIG);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	return 0;
6188c2ecf20Sopenharmony_cierr_epc_mem_exit:
6198c2ecf20Sopenharmony_ci	pci_epc_mem_exit(epc);
6208c2ecf20Sopenharmony_cierr_uninit_port:
6218c2ecf20Sopenharmony_ci	rockchip_pcie_deinit_phys(rockchip);
6228c2ecf20Sopenharmony_cierr_disable_clocks:
6238c2ecf20Sopenharmony_ci	rockchip_pcie_disable_clocks(rockchip);
6248c2ecf20Sopenharmony_ci	return err;
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_cistatic struct platform_driver rockchip_pcie_ep_driver = {
6288c2ecf20Sopenharmony_ci	.driver = {
6298c2ecf20Sopenharmony_ci		.name = "rockchip-pcie-ep",
6308c2ecf20Sopenharmony_ci		.of_match_table = rockchip_pcie_ep_of_match,
6318c2ecf20Sopenharmony_ci	},
6328c2ecf20Sopenharmony_ci	.probe = rockchip_pcie_ep_probe,
6338c2ecf20Sopenharmony_ci};
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cibuiltin_platform_driver(rockchip_pcie_ep_driver);
636