GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,34 @@
# SPDX-License-Identifier: GPL-2.0
#
# PCI Endpoint Support
#
menu "PCI Endpoint"
config PCI_ENDPOINT
bool "PCI Endpoint Support"
depends on DM
help
Enable this configuration option to support configurable PCI
endpoints. This should be enabled if the platform has a PCI
controllers that can operate in endpoint mode (as a device
connected to PCI host or bridge).
config PCIE_CADENCE_EP
bool "Cadence PCIe endpoint controller"
depends on PCI_ENDPOINT
help
Say Y here if you want to support the Cadence PCIe controller in
endpoint mode. This PCIe controller may be embedded into many
different vendors SoCs.
config PCI_SANDBOX_EP
bool "Sandbox PCIe endpoint controller"
depends on PCI_ENDPOINT
help
Say Y here if you want to support the Sandbox PCIe controller in
endpoint mode.
The sandbox driver act as a dummy driver which stores and
retrieves PCIe endpoint configuration as is.
endmenu
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2019
# Ramon Fried <ramon.fried@gmail.com>
obj-y += pci_ep-uclass.o
obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
obj-$(CONFIG_PCI_SANDBOX_EP) += sandbox-pci_ep.o
@@ -0,0 +1,211 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* PCI Endpoint uclass
*
* Based on Linux PCI-EP driver written by
* Kishon Vijay Abraham I <kishon@ti.com>
*
* Copyright (c) 2019
* Written by Ramon Fried <ramon.fried@gmail.com>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <linux/log2.h>
#include <pci_ep.h>
DECLARE_GLOBAL_DATA_PTR;
int pci_ep_write_header(struct udevice *dev, uint fn, struct pci_ep_header *hdr)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
if (!ops->write_header)
return -ENOSYS;
return ops->write_header(dev, fn, hdr);
}
int pci_ep_read_header(struct udevice *dev, uint fn, struct pci_ep_header *hdr)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
if (!ops->read_header)
return -ENOSYS;
return ops->read_header(dev, fn, hdr);
}
int pci_ep_set_bar(struct udevice *dev, uint func_no, struct pci_bar *ep_bar)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
int flags = ep_bar->flags;
/* Some basic bar validity checks */
if (ep_bar->barno > BAR_5 || ep_bar->barno < BAR_0)
return -EINVAL;
if ((ep_bar->barno == BAR_5 &&
(flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) ||
((flags & PCI_BASE_ADDRESS_SPACE_IO) &&
(flags & PCI_BASE_ADDRESS_IO_MASK)) ||
(upper_32_bits(ep_bar->size) &&
!(flags & PCI_BASE_ADDRESS_MEM_TYPE_64)))
return -EINVAL;
if (!ops->set_bar)
return -ENOSYS;
return ops->set_bar(dev, func_no, ep_bar);
}
int pci_ep_read_bar(struct udevice *dev, uint func_no, struct pci_bar *ep_bar,
enum pci_barno barno)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
/* Some basic bar validity checks */
if (barno > BAR_5 || barno < BAR_0)
return -EINVAL;
if (!ops->read_bar)
return -ENOSYS;
return ops->read_bar(dev, func_no, ep_bar, barno);
}
int pci_ep_clear_bar(struct udevice *dev, uint func_num, enum pci_barno bar)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
if (!ops->clear_bar)
return -ENOSYS;
return ops->clear_bar(dev, func_num, bar);
}
int pci_ep_map_addr(struct udevice *dev, uint func_no, phys_addr_t addr,
u64 pci_addr, size_t size)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
if (!ops->map_addr)
return -ENOSYS;
return ops->map_addr(dev, func_no, addr, pci_addr, size);
}
int pci_ep_unmap_addr(struct udevice *dev, uint func_no, phys_addr_t addr)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
if (!ops->unmap_addr)
return -ENOSYS;
return ops->unmap_addr(dev, func_no, addr);
}
int pci_ep_set_msi(struct udevice *dev, uint func_no, uint interrupts)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
uint encode_int;
if (interrupts > 32)
return -EINVAL;
if (!ops->set_msi)
return -ENOSYS;
/* MSI spec permits allocation of
* only 1, 2, 4, 8, 16, 32 interrupts
*/
encode_int = order_base_2(interrupts);
return ops->set_msi(dev, func_no, encode_int);
}
int pci_ep_get_msi(struct udevice *dev, uint func_no)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
int interrupt;
if (!ops->get_msi)
return -ENOSYS;
interrupt = ops->get_msi(dev, func_no);
if (interrupt < 0)
return 0;
/* Translate back from order base 2*/
interrupt = 1 << interrupt;
return interrupt;
}
int pci_ep_set_msix(struct udevice *dev, uint func_no, uint interrupts)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
if (interrupts < 1 || interrupts > 2048)
return -EINVAL;
if (!ops->set_msix)
return -ENOSYS;
return ops->set_msix(dev, func_no, interrupts - 1);
}
int pci_ep_get_msix(struct udevice *dev, uint func_no)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
int interrupt;
if (!ops->get_msix)
return -ENOSYS;
interrupt = ops->get_msix(dev, func_no);
if (interrupt < 0)
return 0;
return interrupt + 1;
}
int pci_ep_raise_irq(struct udevice *dev, uint func_no,
enum pci_ep_irq_type type, uint interrupt_num)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
if (!ops->raise_irq)
return -ENOSYS;
return ops->raise_irq(dev, func_no, type, interrupt_num);
}
int pci_ep_start(struct udevice *dev)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
if (!ops->start)
return -ENOSYS;
return ops->start(dev);
}
int pci_ep_stop(struct udevice *dev)
{
struct pci_ep_ops *ops = pci_ep_get_ops(dev);
if (!ops->stop)
return -ENOSYS;
return ops->stop(dev);
}
UCLASS_DRIVER(pci_ep) = {
.id = UCLASS_PCI_EP,
.name = "pci_ep",
.flags = DM_UC_FLAG_SEQ_ALIAS,
};
@@ -0,0 +1,177 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2019
* Written by Ramon Fried <ramon.fried@gmail.com>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <pci_ep.h>
#include <linux/sizes.h>
#include <linux/log2.h>
#include "pcie-cadence.h"
DECLARE_GLOBAL_DATA_PTR;
static int cdns_write_header(struct udevice *dev, uint fn,
struct pci_ep_header *hdr)
{
struct cdns_pcie *pcie = dev_get_priv(dev);
cdns_pcie_ep_fn_writew(pcie, fn, PCI_DEVICE_ID, hdr->deviceid);
cdns_pcie_ep_fn_writeb(pcie, fn, PCI_REVISION_ID, hdr->revid);
cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CLASS_PROG,
hdr->progif_code);
cdns_pcie_ep_fn_writew(pcie, fn, PCI_CLASS_DEVICE,
hdr->subclass_code |
hdr->baseclass_code << 8);
cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CACHE_LINE_SIZE,
hdr->cache_line_size);
cdns_pcie_ep_fn_writew(pcie, fn, PCI_SUBSYSTEM_ID,
hdr->subsys_id);
cdns_pcie_ep_fn_writeb(pcie, fn, PCI_INTERRUPT_PIN,
hdr->interrupt_pin);
/*
* Vendor ID can only be modified from function 0, all other functions
* use the same vendor ID as function 0.
*/
if (fn == 0) {
/* Update the vendor IDs. */
u32 id = CDNS_PCIE_LM_ID_VENDOR(hdr->vendorid) |
CDNS_PCIE_LM_ID_SUBSYS(hdr->subsys_vendor_id);
cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id);
}
return 0;
}
static int cdns_set_bar(struct udevice *dev, uint fn, struct pci_bar *ep_bar)
{
struct cdns_pcie *pcie = dev_get_priv(dev);
dma_addr_t bar_phys = ep_bar->phys_addr;
enum pci_barno bar = ep_bar->barno;
int flags = ep_bar->flags;
u32 addr0, addr1, reg, cfg, b, aperture, ctrl;
u64 sz;
/* BAR size is 2^(aperture + 7) */
sz = max_t(size_t, ep_bar->size, CDNS_PCIE_EP_MIN_APERTURE);
/*
* roundup_pow_of_two() returns an unsigned long, which is not suited
* for 64bit values.
*/
sz = 1ULL << fls64(sz - 1);
aperture = ilog2(sz) - 7; /* 128B -> 0, 256B -> 1, 512B -> 2, ... */
if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS;
} else {
bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH);
bool is_64bits = (sz > SZ_2G) |
!!(ep_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64);
if (is_64bits && (bar & 1))
return -EINVAL;
if (is_64bits && !(flags & PCI_BASE_ADDRESS_MEM_TYPE_64))
ep_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
if (is_64bits && is_prefetch)
ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS;
else if (is_prefetch)
ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS;
else if (is_64bits)
ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS;
else
ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS;
}
addr0 = lower_32_bits(bar_phys);
addr1 = upper_32_bits(bar_phys);
cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar),
addr0);
cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar),
addr1);
if (bar < BAR_4) {
reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn);
b = bar;
} else {
reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn);
b = bar - BAR_4;
}
cfg = cdns_pcie_readl(pcie, reg);
cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
cfg |= (CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) |
CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
cdns_pcie_writel(pcie, reg, cfg);
return 0;
}
static int cdns_set_msi(struct udevice *dev, uint fn, uint mmc)
{
struct cdns_pcie *pcie = dev_get_priv(dev);
u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
/*
* Set the Multiple Message Capable bitfield into the Message Control
* register.
*/
u16 flags;
flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
flags = (flags & ~PCI_MSI_FLAGS_QMASK) | (mmc << 1);
flags |= PCI_MSI_FLAGS_64BIT;
flags &= ~PCI_MSI_FLAGS_MASKBIT;
cdns_pcie_ep_fn_writew(pcie, fn, cap + PCI_MSI_FLAGS, flags);
return 0;
}
static struct pci_ep_ops cdns_pci_ep_ops = {
.write_header = cdns_write_header,
.set_bar = cdns_set_bar,
.set_msi = cdns_set_msi,
};
static int cdns_pci_ep_probe(struct udevice *dev)
{
struct cdns_pcie *pdata = dev_get_priv(dev);
pdata->reg_base = (void __iomem *)devfdt_get_addr(dev);
if (!pdata->reg_base)
return -ENOMEM;
pdata->max_functions = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"max-functions", 1);
pdata->max_regions = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"cdns,max-outbound-regions", 8);
return 0;
}
static int cdns_pci_ep_remove(struct udevice *dev)
{
return 0;
}
const struct udevice_id cadence_pci_ep_of_match[] = {
{ .compatible = "cdns,cdns-pcie-ep" },
{ }
};
U_BOOT_DRIVER(cdns_pcie) = {
.name = "cdns,pcie-ep",
.id = UCLASS_PCI_EP,
.of_match = cadence_pci_ep_of_match,
.ops = &cdns_pci_ep_ops,
.probe = cdns_pci_ep_probe,
.remove = cdns_pci_ep_remove,
.priv_auto_alloc_size = sizeof(struct cdns_pcie),
};
@@ -0,0 +1,309 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Cadence PCIe controlloer definitions
* Adapted from linux kernel driver.
* Copyright (c) 2017 Cadence
*
* Copyright (c) 2019
* Written by Ramon Fried <ramon.fried@gmail.com>
*/
#ifndef PCIE_CADENCE_H
#define PCIE_CADENCE_H
#include <common.h>
#include <pci_ep.h>
#include <asm/io.h>
/*
* Local Management Registers
*/
#define CDNS_PCIE_LM_BASE 0x00100000
/* Vendor ID Register */
#define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044)
#define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0)
#define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0
#define CDNS_PCIE_LM_ID_VENDOR(vid) \
(((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK)
#define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16)
#define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16
#define CDNS_PCIE_LM_ID_SUBSYS(sub) \
(((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK)
/* Root Port Requestor ID Register */
#define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228)
#define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0)
#define CDNS_PCIE_LM_RP_RID_SHIFT 0
#define CDNS_PCIE_LM_RP_RID_(rid) \
(((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK)
/* Endpoint Bus and Device Number Register */
#define CDNS_PCIE_LM_EP_ID (CDNS_PCIE_LM_BASE + 0x022c)
#define CDNS_PCIE_LM_EP_ID_DEV_MASK GENMASK(4, 0)
#define CDNS_PCIE_LM_EP_ID_DEV_SHIFT 0
#define CDNS_PCIE_LM_EP_ID_BUS_MASK GENMASK(15, 8)
#define CDNS_PCIE_LM_EP_ID_BUS_SHIFT 8
/* Endpoint Function f BAR b Configuration Registers */
#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn) \
(CDNS_PCIE_LM_BASE + 0x0240 + (fn) * 0x0008)
#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn) \
(CDNS_PCIE_LM_BASE + 0x0244 + (fn) * 0x0008)
#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) \
(GENMASK(4, 0) << ((b) * 8))
#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, a) \
(((a) << ((b) * 8)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b))
#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b) \
(GENMASK(7, 5) << ((b) * 8))
#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, c) \
(((c) << ((b) * 8 + 5)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b))
/* Endpoint Function Configuration Register */
#define CDNS_PCIE_LM_EP_FUNC_CFG (CDNS_PCIE_LM_BASE + 0x02c0)
/* Root Complex BAR Configuration Register */
#define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300)
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(5, 0)
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \
(((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK)
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6)
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \
(((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK)
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(13, 9)
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \
(((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK)
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14)
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \
(((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK)
#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17)
#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS 0
#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18)
#define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19)
#define CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS 0
#define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20)
#define CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE BIT(31)
/* BAR control values applicable to both Endpoint Function and Root Complex */
#define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0
#define CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS 0x1
#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4
#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5
#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6
#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7
/*
* Endpoint Function Registers (PCI configuration space for endpoint functions)
*/
#define CDNS_PCIE_EP_FUNC_BASE(fn) (((fn) << 12) & GENMASK(19, 12))
#define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET 0x90
/*
* Root Port Registers (PCI configuration space for the root port function)
*/
#define CDNS_PCIE_RP_BASE 0x00200000
/*
* Address Translation Registers
*/
#define CDNS_PCIE_AT_BASE 0x00400000
/* Region r Outbound AXI to PCIe Address Translation Register 0 */
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
(CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020)
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0)
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \
(((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK)
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12)
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
(((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK)
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20)
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
(((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
/* Region r Outbound AXI to PCIe Address Translation Register 1 */
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
(CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020)
/* Region r Outbound PCIe Descriptor Register 0 */
#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \
(CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020)
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(3, 0)
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xa
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xb
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG 0xc
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG 0xd
/* Bit 23 MUST be set in RC mode. */
#define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23)
#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24)
#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
(((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
/* Region r Outbound PCIe Descriptor Register 1 */
#define CDNS_PCIE_AT_OB_REGION_DESC1(r) \
(CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020)
#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0)
#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \
((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK)
/* Region r AXI Region Base Address Register 0 */
#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
(CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020)
#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0)
#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \
(((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK)
/* Region r AXI Region Base Address Register 1 */
#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
(CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020)
/* Root Port BAR Inbound PCIe to AXI Address Translation Register */
#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \
(CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008)
#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0)
#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \
(((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK)
#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \
(CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008)
/* AXI link down register */
#define CDNS_PCIE_AT_LINKDOWN (CDNS_PCIE_AT_BASE + 0x0824)
enum cdns_pcie_rp_bar {
RP_BAR0,
RP_BAR1,
RP_NO_BAR
};
/* Endpoint Function BAR Inbound PCIe to AXI Address Translation Register */
#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
(CDNS_PCIE_AT_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) \
(CDNS_PCIE_AT_BASE + 0x0844 + (fn) * 0x0040 + (bar) * 0x0008)
/* Normal/Vendor specific message access: offset inside some outbound region */
#define CDNS_PCIE_NORMAL_MSG_ROUTING_MASK GENMASK(7, 5)
#define CDNS_PCIE_NORMAL_MSG_ROUTING(route) \
(((route) << 5) & CDNS_PCIE_NORMAL_MSG_ROUTING_MASK)
#define CDNS_PCIE_NORMAL_MSG_CODE_MASK GENMASK(15, 8)
#define CDNS_PCIE_NORMAL_MSG_CODE(code) \
(((code) << 8) & CDNS_PCIE_NORMAL_MSG_CODE_MASK)
#define CDNS_PCIE_MSG_NO_DATA BIT(16)
#define CDNS_PCIE_EP_MIN_APERTURE 128 /* 128 bytes */
enum cdns_pcie_msg_code {
MSG_CODE_ASSERT_INTA = 0x20,
MSG_CODE_ASSERT_INTB = 0x21,
MSG_CODE_ASSERT_INTC = 0x22,
MSG_CODE_ASSERT_INTD = 0x23,
MSG_CODE_DEASSERT_INTA = 0x24,
MSG_CODE_DEASSERT_INTB = 0x25,
MSG_CODE_DEASSERT_INTC = 0x26,
MSG_CODE_DEASSERT_INTD = 0x27,
};
enum cdns_pcie_msg_routing {
/* Route to Root Complex */
MSG_ROUTING_TO_RC,
/* Use Address Routing */
MSG_ROUTING_BY_ADDR,
/* Use ID Routing */
MSG_ROUTING_BY_ID,
/* Route as Broadcast Message from Root Complex */
MSG_ROUTING_BCAST,
/* Local message; terminate at receiver (INTx messages) */
MSG_ROUTING_LOCAL,
/* Gather & route to Root Complex (PME_TO_Ack message) */
MSG_ROUTING_GATHER,
};
struct cdns_pcie {
void __iomem *reg_base;
u32 max_functions;
u32 max_regions;
};
/* Register access */
static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value)
{
writeb(value, pcie->reg_base + reg);
}
static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
{
writew(value, pcie->reg_base + reg);
}
static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
{
writel(value, pcie->reg_base + reg);
}
static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
{
return readl(pcie->reg_base + reg);
}
/* Root Port register access */
static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie,
u32 reg, u8 value)
{
writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
}
static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
u32 reg, u16 value)
{
writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
}
static inline void cdns_pcie_rp_writel(struct cdns_pcie *pcie,
u32 reg, u32 value)
{
writel(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
}
/* Endpoint Function register access */
static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
u32 reg, u8 value)
{
writeb(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
}
static inline void cdns_pcie_ep_fn_writew(struct cdns_pcie *pcie, u8 fn,
u32 reg, u16 value)
{
writew(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
}
static inline void cdns_pcie_ep_fn_writel(struct cdns_pcie *pcie, u8 fn,
u32 reg, u32 value)
{
writel(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
}
static inline u8 cdns_pcie_ep_fn_readb(struct cdns_pcie *pcie, u8 fn, u32 reg)
{
return readb(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
}
static inline u16 cdns_pcie_ep_fn_readw(struct cdns_pcie *pcie, u8 fn, u32 reg)
{
return readw(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
}
static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg)
{
return readl(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
}
#endif /* end of include guard: PCIE_CADENCE_H */
@@ -0,0 +1,179 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2019 Ramon Fried <ramon.fried@gmail.com>
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <pci.h>
#include <pci_ep.h>
#include <asm/test.h>
/**
* struct sandbox_pci_ep_priv - private data for driver
* @hdr: Stores the EP device header
* @msix: required MSIx count;
* @msi: required MSI count;
*/
struct sandbox_pci_ep_priv {
struct pci_ep_header hdr;
struct pci_bar bars[6];
int msix;
int msi;
int irq_count;
};
/* Method exported for testing purposes */
int sandbox_get_pci_ep_irq_count(struct udevice *dev)
{
struct sandbox_pci_ep_priv *priv = dev_get_priv(dev);
return priv->irq_count;
}
static const struct udevice_id sandbox_pci_ep_ids[] = {
{ .compatible = "sandbox,pci_ep" },
{ }
};
static int sandbox_write_header(struct udevice *dev, uint fn,
struct pci_ep_header *hdr)
{
struct sandbox_pci_ep_priv *priv = dev_get_priv(dev);
if (fn > 0)
return -ENODEV;
memcpy(&priv->hdr, hdr, sizeof(*hdr));
return 0;
}
static int sandbox_read_header(struct udevice *dev, uint fn,
struct pci_ep_header *hdr)
{
struct sandbox_pci_ep_priv *priv = dev_get_priv(dev);
if (fn > 0)
return -ENODEV;
memcpy(hdr, &priv->hdr, sizeof(*hdr));
return 0;
}
static int sandbox_set_bar(struct udevice *dev, uint fn,
struct pci_bar *ep_bar)
{
struct sandbox_pci_ep_priv *priv = dev_get_priv(dev);
int bar_idx;
if (fn > 0)
return -ENODEV;
bar_idx = ep_bar->barno;
memcpy(&priv->bars[bar_idx], ep_bar, sizeof(*ep_bar));
return 0;
}
static int sandbox_read_bar(struct udevice *dev, uint fn,
struct pci_bar *ep_bar, enum pci_barno barno)
{
struct sandbox_pci_ep_priv *priv = dev_get_priv(dev);
if (fn > 0)
return -ENODEV;
memcpy(ep_bar, &priv->bars[barno], sizeof(*ep_bar));
return 0;
}
static int sandbox_set_msi(struct udevice *dev, uint fn, uint interrupts)
{
struct sandbox_pci_ep_priv *priv = dev_get_priv(dev);
if (fn > 0)
return -ENODEV;
priv->msi = interrupts;
return 0;
}
static int sandbox_get_msi(struct udevice *dev, uint fn)
{
struct sandbox_pci_ep_priv *priv = dev_get_priv(dev);
if (fn > 0)
return -ENODEV;
return priv->msi;
}
static int sandbox_set_msix(struct udevice *dev, uint fn, uint interrupts)
{
struct sandbox_pci_ep_priv *priv = dev_get_priv(dev);
if (fn > 0)
return -ENODEV;
priv->msix = interrupts;
return 0;
}
static int sandbox_get_msix(struct udevice *dev, uint fn)
{
struct sandbox_pci_ep_priv *priv = dev_get_priv(dev);
if (fn > 0)
return -ENODEV;
return priv->msix;
}
static int sandbox_raise_irq(struct udevice *dev, uint fn,
enum pci_ep_irq_type type, uint interrupt_num)
{
struct sandbox_pci_ep_priv *priv = dev_get_priv(dev);
if (fn > 0)
return -ENODEV;
priv->irq_count++;
return 0;
}
static int sandbox_pci_ep_probe(struct udevice *dev)
{
struct sandbox_pci_ep_priv *priv = dev_get_priv(dev);
memset(priv, 0, sizeof(*priv));
return 0;
}
static struct pci_ep_ops sandbox_pci_ep_ops = {
.write_header = sandbox_write_header,
.read_header = sandbox_read_header,
.set_bar = sandbox_set_bar,
.read_bar = sandbox_read_bar,
.set_msi = sandbox_set_msi,
.get_msi = sandbox_get_msi,
.set_msix = sandbox_set_msix,
.get_msix = sandbox_get_msix,
.raise_irq = sandbox_raise_irq,
};
U_BOOT_DRIVER(pci_ep_sandbox) = {
.name = "pci_ep_sandbox",
.id = UCLASS_PCI_EP,
.of_match = sandbox_pci_ep_ids,
.probe = sandbox_pci_ep_probe,
.ops = &sandbox_pci_ep_ops,
.priv_auto_alloc_size = sizeof(struct sandbox_pci_ep_priv),
};