blob: 6bf284bff2c023506ab3ec7a19f9862d32c1fb94 [file] [log] [blame]
/*
* Copyright (c) 2019 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <drivers/pcie/pcie.h>
#ifdef CONFIG_PCIE_MSI
#include <drivers/pcie/msi.h>
#endif
/*
* The Configuration Mechanism (previously, Configuration Mechanism #1)
* uses two 32-bit ports in the I/O space, here called CAP and CDP.
*
* N.B.: this code relies on the fact that the PCIE_BDF() format (as
* defined in dt-bindings/pcie/pcie.h) and the CAP agree on the bus/dev/func
* bitfield positions and sizes.
*/
#define PCIE_X86_CAP 0xCF8U /* Configuration Address Port */
#define PCIE_X86_CAP_BDF_MASK 0x00FFFF00U /* b/d/f bits */
#define PCIE_X86_CAP_EN 0x80000000U /* enable bit */
#define PCIE_X86_CAP_WORD_MASK 0x3FU /* 6-bit word index .. */
#define PCIE_X86_CAP_WORD_SHIFT 2U /* .. is in CAP[7:2] */
#define PCIE_X86_CDP 0xCFCU /* Configuration Data Port */
/*
* Helper function for exported configuration functions. Configuration access
* ain't atomic, so spinlock to keep drivers from clobbering each other.
*/
static void pcie_conf(pcie_bdf_t bdf, unsigned int reg, bool write, u32_t *data)
{
static struct k_spinlock lock;
k_spinlock_key_t k;
bdf &= PCIE_X86_CAP_BDF_MASK;
bdf |= PCIE_X86_CAP_EN;
bdf |= (reg & PCIE_X86_CAP_WORD_MASK) << PCIE_X86_CAP_WORD_SHIFT;
k = k_spin_lock(&lock);
sys_out32(bdf, PCIE_X86_CAP);
if (write) {
sys_out32(*data, PCIE_X86_CDP);
} else {
*data = sys_in32(PCIE_X86_CDP);
}
sys_out32(0U, PCIE_X86_CAP);
k_spin_unlock(&lock, k);
}
/* these functions are explained in include/drivers/pcie/pcie.h */
u32_t pcie_conf_read(pcie_bdf_t bdf, unsigned int reg)
{
u32_t data;
pcie_conf(bdf, reg, false, &data);
return data;
}
void pcie_conf_write(pcie_bdf_t bdf, unsigned int reg, u32_t data)
{
pcie_conf(bdf, reg, true, &data);
}
#ifdef CONFIG_PCIE_MSI
/* these functions are explained in include/drivers/pcie/msi.h */
u32_t pcie_msi_map(unsigned int irq)
{
ARG_UNUSED(irq);
return 0xFEE00000U; /* standard delivery to BSP local APIC */
}
u16_t pcie_msi_mdr(unsigned int irq)
{
unsigned char vector = Z_IRQ_TO_INTERRUPT_VECTOR(irq);
return 0x4000U | vector; /* edge triggered */
}
#endif