drivers/pci: remove legacy PCI implementation
This has been subsumed by the new implementation in drivers/pcie. We remove the legacy subsystem, related tests, shell module, and outdated documentation/config references. Signed-off-by: Charles E. Youse <charles.youse@intel.com>
This commit is contained in:
parent
34ffdd0aab
commit
4a166f4913
16 changed files with 0 additions and 3004 deletions
|
@ -137,7 +137,6 @@
|
||||||
/drivers/led/ @Mani-Sadhasivam
|
/drivers/led/ @Mani-Sadhasivam
|
||||||
/drivers/led_strip/ @mbolivar
|
/drivers/led_strip/ @mbolivar
|
||||||
/drivers/modem/ @mike-scott
|
/drivers/modem/ @mike-scott
|
||||||
/drivers/pci/ @gnuless
|
|
||||||
/drivers/pcie/ @gnuless
|
/drivers/pcie/ @gnuless
|
||||||
/drivers/pinmux/stm32/ @rsalveti @idlethread
|
/drivers/pinmux/stm32/ @rsalveti @idlethread
|
||||||
/drivers/sensor/ @MaureenHelm
|
/drivers/sensor/ @MaureenHelm
|
||||||
|
|
|
@ -20,7 +20,6 @@ add_subdirectory_if_kconfig(ipm)
|
||||||
add_subdirectory_if_kconfig(led)
|
add_subdirectory_if_kconfig(led)
|
||||||
add_subdirectory_if_kconfig(led_strip)
|
add_subdirectory_if_kconfig(led_strip)
|
||||||
add_subdirectory_if_kconfig(modem)
|
add_subdirectory_if_kconfig(modem)
|
||||||
add_subdirectory_if_kconfig(pci)
|
|
||||||
add_subdirectory_if_kconfig(pcie)
|
add_subdirectory_if_kconfig(pcie)
|
||||||
add_subdirectory_if_kconfig(pinmux)
|
add_subdirectory_if_kconfig(pinmux)
|
||||||
add_subdirectory_if_kconfig(pwm)
|
add_subdirectory_if_kconfig(pwm)
|
||||||
|
|
|
@ -27,8 +27,6 @@ source "drivers/timer/Kconfig"
|
||||||
|
|
||||||
source "drivers/entropy/Kconfig"
|
source "drivers/entropy/Kconfig"
|
||||||
|
|
||||||
source "drivers/pci/Kconfig"
|
|
||||||
|
|
||||||
source "drivers/pcie/Kconfig"
|
source "drivers/pcie/Kconfig"
|
||||||
|
|
||||||
source "drivers/gpio/Kconfig"
|
source "drivers/gpio/Kconfig"
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
zephyr_sources(
|
|
||||||
pci.c
|
|
||||||
pci_config.c
|
|
||||||
pci_interface.c
|
|
||||||
)
|
|
||||||
zephyr_sources_ifdef(CONFIG_PCI_SHELL pci_shell.c)
|
|
|
@ -1,38 +0,0 @@
|
||||||
# Kconfig - PCI configuration options
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright (c) 2015 Intel Corporation
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
menuconfig PCI
|
|
||||||
bool "PCI Settings"
|
|
||||||
depends on X86
|
|
||||||
help
|
|
||||||
This options enables support of PCI bus for device drivers.
|
|
||||||
|
|
||||||
if PCI
|
|
||||||
|
|
||||||
config PCI_SHELL
|
|
||||||
bool "Enable PCI Shell"
|
|
||||||
depends on SHELL
|
|
||||||
select PCI_ENUMERATION
|
|
||||||
help
|
|
||||||
Enable commands for debugging PCI using the built-in shell.
|
|
||||||
|
|
||||||
config PCI_ENUMERATION
|
|
||||||
bool "Enable PCI device enumeration"
|
|
||||||
help
|
|
||||||
This option enables the PCI enumeration for device drivers.
|
|
||||||
This might be useful to find out which are the PCI settings
|
|
||||||
of the devices. Once those are known and statically set in
|
|
||||||
every relevant driver's configuration, it might be wise to
|
|
||||||
disable this option to remove useless code.
|
|
||||||
|
|
||||||
module = PCI
|
|
||||||
module-str = PCI
|
|
||||||
source "subsys/logging/Kconfig.template.log_config"
|
|
||||||
|
|
||||||
endif # PCI
|
|
|
@ -1,476 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2013-2014 Wind River Systems, Inc.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief PCI probe and information routines
|
|
||||||
*
|
|
||||||
* Module implements routines for PCI bus initialization and query.
|
|
||||||
*
|
|
||||||
* USAGE
|
|
||||||
* To use the driver, the platform must define:
|
|
||||||
* - Numbers of BUSes:
|
|
||||||
* - PCI_BUS_NUMBERS;
|
|
||||||
* - Register addresses:
|
|
||||||
* - PCI_CTRL_ADDR_REG;
|
|
||||||
* - PCI_CTRL_DATA_REG;
|
|
||||||
* - pci_pin2irq() - the routine that converts the PCI interrupt pin
|
|
||||||
* number to IRQ number.
|
|
||||||
*
|
|
||||||
* About scanning the PCI buses:
|
|
||||||
* At every new usage of this API, the code should call pci_bus_scan_init().
|
|
||||||
* It should own a struct pci_dev_info, filled in with the parameters it is
|
|
||||||
* interested to look for: class and/or vendor_id/device_id.
|
|
||||||
*
|
|
||||||
* Then it can loop on pci_bus_scan() providing a pointer on that structure.
|
|
||||||
* Such function can be called as long as it returns 1. At every successful
|
|
||||||
* return of pci_bus_scan() it means the provided structure pointer will have
|
|
||||||
* been updated with the current scan result which the code might be interested
|
|
||||||
* in. On pci_bus_scan() returning 0, the code should discard the result and
|
|
||||||
* stop calling pci_bus_scan(). If it wants to retrieve the result, it will
|
|
||||||
* have to restart the procedure all over again.
|
|
||||||
*
|
|
||||||
* EXAMPLE
|
|
||||||
* struct pci_dev_info info = {
|
|
||||||
* .class_type = PCI_CLASS_COMM_CTLR
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* pci_bus_scan_init();
|
|
||||||
*
|
|
||||||
* while (pci_bus_scan(&info)) {
|
|
||||||
* ...
|
|
||||||
* do something with "info" which holds a valid result, i.e. some
|
|
||||||
* device information matching the PCI class PCI_CLASS_COMM_CTLR
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* INTERNALS
|
|
||||||
* The whole logic runs around a structure: struct lookup_data, which exists
|
|
||||||
* on one instantiation called 'lookup'.
|
|
||||||
* Such structure is used for 2 distinct roles:
|
|
||||||
* - to match devices the caller is looking for
|
|
||||||
* - to loop on PCI bus, devices, function and BARs
|
|
||||||
*
|
|
||||||
* The search criteria are the class and/or the vendor_id/device_id of a PCI
|
|
||||||
* device. The caller first initializes the lookup structure by calling
|
|
||||||
* pci_bus_scan_init(), which will reset the search criteria as well as the
|
|
||||||
* loop parameters to 0. At the very first subsequent call of pci_bus_scan()
|
|
||||||
* the lookup structure will store the search criteria. Then the loop starts.
|
|
||||||
* For each bus it will run through each device on which it will loop on each
|
|
||||||
* function and BARs, as long as the criteria does not match or until it hit
|
|
||||||
* the limit of bus/dev/functions to scan.
|
|
||||||
*
|
|
||||||
* On a successful match, it will stop the loop, fill in the caller's
|
|
||||||
* pci_dev_info structure with the found device information, and return 1.
|
|
||||||
* Hopefully, the lookup structure still remembers where it stopped and the
|
|
||||||
* original search criteria. Thus, when the caller asks to scan again for
|
|
||||||
* a possible result next, the loop will restart where it stopped.
|
|
||||||
* That will work as long as there are relevant results found.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <kernel.h>
|
|
||||||
#include <arch/cpu.h>
|
|
||||||
#include <sys/printk.h>
|
|
||||||
#include <toolchain.h>
|
|
||||||
#include <linker/sections.h>
|
|
||||||
|
|
||||||
#include <soc.h>
|
|
||||||
|
|
||||||
#include <pci/pci_mgr.h>
|
|
||||||
#include <pci/pci.h>
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_ENUMERATION
|
|
||||||
|
|
||||||
/* NOTE. These parameters may need to be configurable */
|
|
||||||
#define LSPCI_MAX_BUS PCI_BUS_NUMBERS /* maximum number of buses to scan */
|
|
||||||
#define LSPCI_MAX_DEV 32 /* maximum number of devices to scan */
|
|
||||||
#define LSPCI_MAX_FUNC PCI_MAX_FUNCTIONS /* maximum functions to scan */
|
|
||||||
#define LSPCI_MAX_REG 64 /* maximum device registers to read */
|
|
||||||
|
|
||||||
/* Base Address Register configuration fields */
|
|
||||||
|
|
||||||
#define BAR_SPACE(x) ((x) & 0x00000001)
|
|
||||||
|
|
||||||
#define BAR_TYPE(x) ((x) & 0x00000006)
|
|
||||||
#define BAR_TYPE_32BIT 0
|
|
||||||
#define BAR_TYPE_64BIT 4
|
|
||||||
|
|
||||||
#define BAR_PREFETCH(x) (((x) >> 3) & 0x00000001)
|
|
||||||
#define BAR_ADDR(x) (((x) >> 4) & 0x0fffffff)
|
|
||||||
|
|
||||||
#define BAR_IO_MASK(x) ((x) & ~0x3)
|
|
||||||
#define BAR_MEM_MASK(x) ((x) & ~0xf)
|
|
||||||
|
|
||||||
struct lookup_data {
|
|
||||||
struct pci_dev_info info;
|
|
||||||
u32_t bus:9;
|
|
||||||
u32_t dev:6;
|
|
||||||
u32_t func:4;
|
|
||||||
u32_t baridx:3;
|
|
||||||
u32_t barofs:3;
|
|
||||||
u32_t unused:7;
|
|
||||||
u8_t buses;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct lookup_data __noinit lookup;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the configuration for the specified BAR
|
|
||||||
*
|
|
||||||
* @return 0 if BAR is implemented, -1 if not.
|
|
||||||
*/
|
|
||||||
static int pci_bar_config_get(union pci_addr_reg pci_ctrl_addr, u32_t *config)
|
|
||||||
{
|
|
||||||
u32_t old_value;
|
|
||||||
|
|
||||||
/* save the current setting */
|
|
||||||
pci_read(DEFAULT_PCI_CONTROLLER, pci_ctrl_addr,
|
|
||||||
sizeof(old_value), &old_value);
|
|
||||||
|
|
||||||
/* write to the BAR to see how large it is */
|
|
||||||
pci_write(DEFAULT_PCI_CONTROLLER, pci_ctrl_addr,
|
|
||||||
sizeof(u32_t), 0xffffffff);
|
|
||||||
|
|
||||||
pci_read(DEFAULT_PCI_CONTROLLER, pci_ctrl_addr,
|
|
||||||
sizeof(*config), config);
|
|
||||||
|
|
||||||
/* put back the old configuration */
|
|
||||||
pci_write(DEFAULT_PCI_CONTROLLER, pci_ctrl_addr,
|
|
||||||
sizeof(old_value), old_value);
|
|
||||||
|
|
||||||
/* check if this BAR is implemented */
|
|
||||||
if (*config != 0xffffffff && *config != 0U) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* BAR not supported */
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Retrieve the I/O address and IRQ of the specified BAR
|
|
||||||
*
|
|
||||||
* @return -1 on error, 0 if 32 bit BAR retrieved or 1 if 64 bit BAR retrieved
|
|
||||||
*
|
|
||||||
* NOTE: Routine does not set up parameters for 64 bit BARS, they are ignored.
|
|
||||||
*/
|
|
||||||
static int pci_bar_params_get(union pci_addr_reg pci_ctrl_addr,
|
|
||||||
struct pci_dev_info *dev_info,
|
|
||||||
int max_bars)
|
|
||||||
{
|
|
||||||
u32_t bar_value;
|
|
||||||
u32_t bar_config;
|
|
||||||
u32_t bar_hival;
|
|
||||||
u32_t addr;
|
|
||||||
u32_t mask;
|
|
||||||
|
|
||||||
pci_ctrl_addr.field.reg = 4 + lookup.barofs;
|
|
||||||
|
|
||||||
pci_read(DEFAULT_PCI_CONTROLLER, pci_ctrl_addr,
|
|
||||||
sizeof(bar_value), &bar_value);
|
|
||||||
if (pci_bar_config_get(pci_ctrl_addr, &bar_config) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BAR_SPACE(bar_config) == BAR_SPACE_MEM) {
|
|
||||||
dev_info->mem_type = BAR_SPACE_MEM;
|
|
||||||
mask = ~0xf;
|
|
||||||
if (BAR_TYPE(bar_config) == BAR_TYPE_64BIT) {
|
|
||||||
/* Last BAR register cannot be 64-bit */
|
|
||||||
if (++lookup.barofs >= max_bars) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure the address is accessible */
|
|
||||||
pci_ctrl_addr.field.reg++;
|
|
||||||
pci_read(DEFAULT_PCI_CONTROLLER, pci_ctrl_addr,
|
|
||||||
sizeof(bar_hival), &bar_hival);
|
|
||||||
if (bar_hival) {
|
|
||||||
return 1; /* Inaccessible memory */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dev_info->mem_type = BAR_SPACE_IO;
|
|
||||||
mask = ~0x3;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_info->addr = bar_value & mask;
|
|
||||||
|
|
||||||
addr = bar_config & mask;
|
|
||||||
if (addr != 0U) {
|
|
||||||
/* calculate the size of the BAR memory required */
|
|
||||||
dev_info->size = 1 << (find_lsb_set(addr) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool pci_read_multifunction(union pci_addr_reg pci_ctrl_addr)
|
|
||||||
{
|
|
||||||
u32_t header_type;
|
|
||||||
|
|
||||||
pci_ctrl_addr.field.reg = 3;
|
|
||||||
pci_ctrl_addr.field.offset = 0;
|
|
||||||
pci_read(DEFAULT_PCI_CONTROLLER, pci_ctrl_addr, sizeof(header_type),
|
|
||||||
&header_type);
|
|
||||||
|
|
||||||
return header_type >> 16 & 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Scan the specified PCI device for all sub functions
|
|
||||||
*
|
|
||||||
* @return 1 if a device has been found, 0 otherwise.
|
|
||||||
*/
|
|
||||||
static int pci_dev_scan(union pci_addr_reg pci_ctrl_addr,
|
|
||||||
struct pci_dev_info *dev_info)
|
|
||||||
{
|
|
||||||
static union pci_dev pci_dev_header;
|
|
||||||
u32_t pci_data;
|
|
||||||
int max_bars;
|
|
||||||
bool multi_function;
|
|
||||||
|
|
||||||
/* verify first if there is a valid device at this point */
|
|
||||||
pci_ctrl_addr.field.func = 0;
|
|
||||||
|
|
||||||
pci_read(DEFAULT_PCI_CONTROLLER, pci_ctrl_addr,
|
|
||||||
sizeof(pci_data), &pci_data);
|
|
||||||
if (pci_data == 0xffffffff) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check that PCI is multi a function device */
|
|
||||||
multi_function = pci_read_multifunction(pci_ctrl_addr);
|
|
||||||
|
|
||||||
/* scan all the possible functions for this device */
|
|
||||||
for (; lookup.func < LSPCI_MAX_FUNC;
|
|
||||||
lookup.baridx = 0, lookup.barofs = 0, lookup.func++) {
|
|
||||||
if (lookup.info.function != PCI_FUNCTION_ANY &&
|
|
||||||
lookup.func != lookup.info.function) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip single function device */
|
|
||||||
if (lookup.func != 0 && !multi_function) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_ctrl_addr.field.func = lookup.func;
|
|
||||||
|
|
||||||
if (lookup.func != 0) {
|
|
||||||
pci_read(DEFAULT_PCI_CONTROLLER, pci_ctrl_addr,
|
|
||||||
sizeof(pci_data), &pci_data);
|
|
||||||
if (pci_data == 0xffffffff) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get the PCI header from the device */
|
|
||||||
pci_header_get(DEFAULT_PCI_CONTROLLER,
|
|
||||||
pci_ctrl_addr, &pci_dev_header);
|
|
||||||
if (pci_dev_header.field.class == PCI_CLASS_BRIDGE_CTLR &&
|
|
||||||
pci_dev_header.field.subclass == PCI_SUBCLASS_P2P_BRIDGE) {
|
|
||||||
lookup.buses++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Skip a device if its class is specified by the
|
|
||||||
* caller and does not match
|
|
||||||
*/
|
|
||||||
if (lookup.info.class_type &&
|
|
||||||
pci_dev_header.field.class != lookup.info.class_type) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lookup.info.vendor_id && lookup.info.device_id &&
|
|
||||||
(lookup.info.vendor_id != pci_dev_header.field.vendor_id ||
|
|
||||||
lookup.info.device_id != pci_dev_header.field.device_id)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get memory and interrupt information */
|
|
||||||
if ((pci_dev_header.field.hdr_type & 0x7f) == 1) {
|
|
||||||
max_bars = 2;
|
|
||||||
} else {
|
|
||||||
max_bars = PCI_MAX_BARS;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; lookup.barofs < max_bars;
|
|
||||||
lookup.baridx++, lookup.barofs++) {
|
|
||||||
/* Ignore BARs with errors */
|
|
||||||
if (pci_bar_params_get(pci_ctrl_addr, dev_info,
|
|
||||||
max_bars) != 0) {
|
|
||||||
continue;
|
|
||||||
} else if (lookup.info.bar != PCI_BAR_ANY &&
|
|
||||||
lookup.baridx != lookup.info.bar) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
dev_info->bus = lookup.bus;
|
|
||||||
dev_info->dev = lookup.dev;
|
|
||||||
dev_info->vendor_id =
|
|
||||||
pci_dev_header.field.vendor_id;
|
|
||||||
dev_info->device_id =
|
|
||||||
pci_dev_header.field.device_id;
|
|
||||||
dev_info->class_type =
|
|
||||||
pci_dev_header.field.class;
|
|
||||||
dev_info->irq = pci_pin2irq(dev_info->bus,
|
|
||||||
dev_info->dev,
|
|
||||||
pci_dev_header.field.interrupt_pin);
|
|
||||||
dev_info->function = lookup.func;
|
|
||||||
dev_info->bar = lookup.baridx;
|
|
||||||
|
|
||||||
lookup.baridx++;
|
|
||||||
lookup.barofs++;
|
|
||||||
if (lookup.barofs >= max_bars) {
|
|
||||||
lookup.baridx = 0;
|
|
||||||
lookup.barofs = 0;
|
|
||||||
lookup.func++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pci_bus_scan_init(void)
|
|
||||||
{
|
|
||||||
lookup.info.class_type = 0;
|
|
||||||
lookup.info.vendor_id = 0;
|
|
||||||
lookup.info.device_id = 0;
|
|
||||||
lookup.info.function = PCI_FUNCTION_ANY;
|
|
||||||
lookup.info.bar = PCI_BAR_ANY;
|
|
||||||
lookup.bus = 0;
|
|
||||||
lookup.dev = 0;
|
|
||||||
lookup.func = 0;
|
|
||||||
lookup.baridx = 0;
|
|
||||||
lookup.barofs = 0;
|
|
||||||
lookup.buses = LSPCI_MAX_BUS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Scans PCI bus for devices
|
|
||||||
*
|
|
||||||
* The routine scans the PCI bus for the devices on criteria provided in the
|
|
||||||
* given dev_info at first call. Which criteria can be class and/or
|
|
||||||
* vendor_id/device_id.
|
|
||||||
*
|
|
||||||
* @return 1 on success, 0 otherwise. On success, dev_info is filled in with
|
|
||||||
* currently found device information
|
|
||||||
*/
|
|
||||||
int pci_bus_scan(struct pci_dev_info *dev_info)
|
|
||||||
{
|
|
||||||
union pci_addr_reg pci_ctrl_addr;
|
|
||||||
|
|
||||||
bool init_from_dev_info =
|
|
||||||
!lookup.info.class_type &&
|
|
||||||
!lookup.info.vendor_id &&
|
|
||||||
!lookup.info.device_id &&
|
|
||||||
lookup.info.bar == PCI_BAR_ANY &&
|
|
||||||
lookup.info.function == PCI_FUNCTION_ANY;
|
|
||||||
|
|
||||||
if (init_from_dev_info) {
|
|
||||||
lookup.info.class_type = dev_info->class_type;
|
|
||||||
lookup.info.vendor_id = dev_info->vendor_id;
|
|
||||||
lookup.info.device_id = dev_info->device_id;
|
|
||||||
lookup.info.function = dev_info->function;
|
|
||||||
lookup.info.bar = dev_info->bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* initialise the PCI controller address register value */
|
|
||||||
pci_ctrl_addr.value = 0;
|
|
||||||
|
|
||||||
if (lookup.info.function != PCI_FUNCTION_ANY) {
|
|
||||||
lookup.func = lookup.info.function;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* run through the buses and devices */
|
|
||||||
for (; lookup.bus < lookup.buses; lookup.bus++) {
|
|
||||||
for (; lookup.dev < LSPCI_MAX_DEV; lookup.dev++) {
|
|
||||||
if (lookup.bus == 0 && lookup.dev == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_ctrl_addr.field.bus = lookup.bus;
|
|
||||||
pci_ctrl_addr.field.device = lookup.dev;
|
|
||||||
|
|
||||||
if (pci_dev_scan(pci_ctrl_addr, dev_info)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lookup.info.function != PCI_FUNCTION_ANY) {
|
|
||||||
lookup.func = lookup.info.function;
|
|
||||||
} else {
|
|
||||||
lookup.func = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lookup.dev = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_PCI_ENUMERATION */
|
|
||||||
|
|
||||||
static void pci_set_command_bits(struct pci_dev_info *dev_info, u32_t bits)
|
|
||||||
{
|
|
||||||
union pci_addr_reg pci_ctrl_addr;
|
|
||||||
u32_t pci_data;
|
|
||||||
|
|
||||||
pci_ctrl_addr.value = 0;
|
|
||||||
pci_ctrl_addr.field.func = dev_info->function;
|
|
||||||
pci_ctrl_addr.field.bus = dev_info->bus;
|
|
||||||
pci_ctrl_addr.field.device = dev_info->dev;
|
|
||||||
pci_ctrl_addr.field.reg = 1;
|
|
||||||
|
|
||||||
pci_read(DEFAULT_PCI_CONTROLLER, pci_ctrl_addr,
|
|
||||||
sizeof(u16_t), &pci_data);
|
|
||||||
|
|
||||||
pci_data = pci_data | bits;
|
|
||||||
|
|
||||||
pci_write(DEFAULT_PCI_CONTROLLER, pci_ctrl_addr,
|
|
||||||
sizeof(u16_t), pci_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pci_enable_regs(struct pci_dev_info *dev_info)
|
|
||||||
{
|
|
||||||
pci_set_command_bits(dev_info, PCI_CMD_MEM_ENABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pci_enable_bus_master(struct pci_dev_info *dev_info)
|
|
||||||
{
|
|
||||||
pci_set_command_bits(dev_info, PCI_CMD_MASTER_ENABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_LOG_LEVEL_DBG
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Show PCI device
|
|
||||||
*
|
|
||||||
* Shows the PCI device found provided as parameter.
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*/
|
|
||||||
|
|
||||||
void pci_show(struct pci_dev_info *dev_info)
|
|
||||||
{
|
|
||||||
printk("%x:%x.%x %X:%X class: 0x%X, %u, %s, "
|
|
||||||
"addrs: 0x%X-0x%X, IRQ %d\n",
|
|
||||||
dev_info->bus,
|
|
||||||
dev_info->dev,
|
|
||||||
dev_info->function,
|
|
||||||
dev_info->vendor_id,
|
|
||||||
dev_info->device_id,
|
|
||||||
dev_info->class_type,
|
|
||||||
dev_info->bar,
|
|
||||||
(dev_info->mem_type == BAR_SPACE_MEM) ? "MEM" : "I/O",
|
|
||||||
(u32_t)dev_info->addr,
|
|
||||||
(u32_t)(dev_info->addr + dev_info->size - 1),
|
|
||||||
dev_info->irq);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_PCI_LOG_LEVEL_DBG */
|
|
|
@ -1,283 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2009-2010, 2013-2014 Wind River Systems, Inc.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief PCI bus support
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This module implements the PCI config space access functions
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <kernel.h>
|
|
||||||
#include <arch/cpu.h>
|
|
||||||
|
|
||||||
#include <pci/pci_mgr.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Write a 32bit data to pci reg in offset
|
|
||||||
*
|
|
||||||
* @param bus_no Bus number.
|
|
||||||
* @param device_no Device number
|
|
||||||
* @param func_no Function number
|
|
||||||
* @param offset Offset into the configuration space.
|
|
||||||
* @param data Data written to the offset.
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*/
|
|
||||||
void pci_config_out_long(u32_t bus_no, u32_t device_no, u32_t func_no,
|
|
||||||
u32_t offset, u32_t data)
|
|
||||||
{
|
|
||||||
union pci_addr_reg pci_addr;
|
|
||||||
|
|
||||||
/* create the PCI address we're going to access */
|
|
||||||
|
|
||||||
pci_addr.field.bus = bus_no;
|
|
||||||
pci_addr.field.device = device_no;
|
|
||||||
pci_addr.field.func = func_no;
|
|
||||||
pci_addr.field.reg = offset / 4U;
|
|
||||||
pci_addr.field.offset = 0;
|
|
||||||
|
|
||||||
/* write to the PCI controller */
|
|
||||||
|
|
||||||
pci_write(DEFAULT_PCI_CONTROLLER, pci_addr, sizeof(u32_t), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Write a 16bit data to pci reg in offset
|
|
||||||
*
|
|
||||||
* @param bus_no Bus number.
|
|
||||||
* @param device_no Device number.
|
|
||||||
* @param func_no Function number.
|
|
||||||
* @param offset Offset into the configuration space.
|
|
||||||
* @param data Data written to the offset.
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*/
|
|
||||||
void pci_config_out_word(u32_t bus_no, u32_t device_no, u32_t func_no,
|
|
||||||
u32_t offset, u16_t data)
|
|
||||||
{
|
|
||||||
union pci_addr_reg pci_addr;
|
|
||||||
|
|
||||||
/* create the PCI address we're going to access */
|
|
||||||
|
|
||||||
pci_addr.field.bus = bus_no;
|
|
||||||
pci_addr.field.device = device_no;
|
|
||||||
pci_addr.field.func = func_no;
|
|
||||||
pci_addr.field.reg = offset / 4U;
|
|
||||||
pci_addr.field.offset = offset & 2;
|
|
||||||
|
|
||||||
/* write to the PCI controller */
|
|
||||||
|
|
||||||
pci_write(DEFAULT_PCI_CONTROLLER, pci_addr, sizeof(u16_t), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Write a 8bit data to pci reg in offset
|
|
||||||
*
|
|
||||||
* @param bus_no Bus number.
|
|
||||||
* @param device_no Device number.
|
|
||||||
* @param func_no Function number.
|
|
||||||
* @param offset Offset into the configuration space.
|
|
||||||
* @param data Data written to the offset.
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*/
|
|
||||||
void pci_config_out_byte(u32_t bus_no, u32_t device_no, u32_t func_no,
|
|
||||||
u32_t offset, u8_t data)
|
|
||||||
{
|
|
||||||
union pci_addr_reg pci_addr;
|
|
||||||
|
|
||||||
/* create the PCI address we're going to access */
|
|
||||||
|
|
||||||
pci_addr.field.bus = bus_no;
|
|
||||||
pci_addr.field.device = device_no;
|
|
||||||
pci_addr.field.func = func_no;
|
|
||||||
pci_addr.field.reg = offset / 4U;
|
|
||||||
pci_addr.field.offset = offset % 4;
|
|
||||||
|
|
||||||
/* write to the PCI controller */
|
|
||||||
|
|
||||||
pci_write(DEFAULT_PCI_CONTROLLER, pci_addr, sizeof(u8_t), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Read a 32bit data from pci reg in offset
|
|
||||||
*
|
|
||||||
* @param bus_no Bus number.
|
|
||||||
* @param device_no Device number.
|
|
||||||
* @param func_no Function number.
|
|
||||||
* @param offset Offset into the configuration space.
|
|
||||||
* @param data Data read from the offset.
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void pci_config_in_long(u32_t bus_no, u32_t device_no, u32_t func_no,
|
|
||||||
u32_t offset, u32_t *data)
|
|
||||||
{
|
|
||||||
union pci_addr_reg pci_addr;
|
|
||||||
|
|
||||||
/* create the PCI address we're going to access */
|
|
||||||
|
|
||||||
pci_addr.field.bus = bus_no;
|
|
||||||
pci_addr.field.device = device_no;
|
|
||||||
pci_addr.field.func = func_no;
|
|
||||||
pci_addr.field.reg = offset / 4U;
|
|
||||||
pci_addr.field.offset = 0;
|
|
||||||
|
|
||||||
/* read from the PCI controller */
|
|
||||||
|
|
||||||
pci_read(DEFAULT_PCI_CONTROLLER, pci_addr, sizeof(u32_t), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Read in a 16bit data from a pci reg in offset
|
|
||||||
*
|
|
||||||
* @param bus_no Bus number.
|
|
||||||
* @param device_no Device number.
|
|
||||||
* @param func_no Function number.
|
|
||||||
* @param offset Offset into the configuration space.
|
|
||||||
* @param data Data read from the offset.
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
void pci_config_in_word(u32_t bus_no, u32_t device_no, u32_t func_no,
|
|
||||||
u32_t offset, u16_t *data)
|
|
||||||
{
|
|
||||||
union pci_addr_reg pci_addr;
|
|
||||||
u32_t pci_data;
|
|
||||||
|
|
||||||
/* create the PCI address we're going to access */
|
|
||||||
|
|
||||||
pci_addr.field.bus = bus_no;
|
|
||||||
pci_addr.field.device = device_no;
|
|
||||||
pci_addr.field.func = func_no;
|
|
||||||
pci_addr.field.reg = offset / 4U;
|
|
||||||
pci_addr.field.offset = offset & 2;
|
|
||||||
|
|
||||||
/* read from the PCI controller */
|
|
||||||
|
|
||||||
pci_read(DEFAULT_PCI_CONTROLLER, pci_addr, sizeof(u16_t), &pci_data);
|
|
||||||
|
|
||||||
/* return the data */
|
|
||||||
|
|
||||||
*data = (u16_t)pci_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Read in a 8bit data from a pci reg in offset
|
|
||||||
*
|
|
||||||
* @param bus_no Bus number.
|
|
||||||
* @param device_no Device number.
|
|
||||||
* @param func_no Function number.
|
|
||||||
* @param offset Offset into the configuration space.
|
|
||||||
* @param data Data read from the offset.
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
void pci_config_in_byte(u32_t bus_no, u32_t device_no, u32_t func_no,
|
|
||||||
u32_t offset, u8_t *data)
|
|
||||||
{
|
|
||||||
union pci_addr_reg pci_addr;
|
|
||||||
u32_t pci_data;
|
|
||||||
|
|
||||||
/* create the PCI address we're going to access */
|
|
||||||
|
|
||||||
pci_addr.field.bus = bus_no;
|
|
||||||
pci_addr.field.device = device_no;
|
|
||||||
pci_addr.field.func = func_no;
|
|
||||||
pci_addr.field.reg = offset / 4U;
|
|
||||||
pci_addr.field.offset = offset % 4;
|
|
||||||
|
|
||||||
/* read from the PCI controller */
|
|
||||||
|
|
||||||
pci_read(DEFAULT_PCI_CONTROLLER, pci_addr, sizeof(u8_t), &pci_data);
|
|
||||||
|
|
||||||
/* return the data */
|
|
||||||
|
|
||||||
*data = (u8_t)pci_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Find extended capability in ECP linked list
|
|
||||||
*
|
|
||||||
* This routine searches for an extended capability in the linked list of
|
|
||||||
* capabilities in config space. If found, the offset of the first byte
|
|
||||||
* of the capability of interest in config space is returned via pOffset.
|
|
||||||
*
|
|
||||||
* @param ext_cap_find_id Extended capabilities ID to search for.
|
|
||||||
* @param bus PCI bus number.
|
|
||||||
* @param device PCI device number.
|
|
||||||
* @param function PCI function number.
|
|
||||||
* @param p_offset Returned config space offset.
|
|
||||||
*
|
|
||||||
* @return 0 if Extended Capability found, -1 otherwise
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
int pci_config_ext_cap_ptr_find(u8_t ext_cap_find_id, u32_t bus,
|
|
||||||
u32_t device, u32_t function,
|
|
||||||
u8_t *p_offset)
|
|
||||||
{
|
|
||||||
u16_t tmp_stat;
|
|
||||||
u8_t tmp_offset;
|
|
||||||
u8_t cap_offset = 0x00;
|
|
||||||
u8_t cap_id = 0x00;
|
|
||||||
|
|
||||||
/* Check to see if the device has any extended capabilities */
|
|
||||||
|
|
||||||
pci_config_in_word(bus, device, function, PCI_CFG_STATUS, &tmp_stat);
|
|
||||||
|
|
||||||
if ((tmp_stat & PCI_STATUS_NEW_CAP) == 0U) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the initial ECP offset and make longword aligned */
|
|
||||||
|
|
||||||
pci_config_in_byte(bus, device, function, PCI_CFG_CAP_PTR, &cap_offset);
|
|
||||||
cap_offset &= ~0x02;
|
|
||||||
|
|
||||||
/* Bounds check the ECP offset */
|
|
||||||
|
|
||||||
if (cap_offset < 0x40) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Look for the specified Extended Cap item in the linked list */
|
|
||||||
|
|
||||||
while (cap_offset != 0x00) {
|
|
||||||
|
|
||||||
/* Get the Capability ID and check */
|
|
||||||
|
|
||||||
pci_config_in_byte(bus, device, function, (int)cap_offset, &cap_id);
|
|
||||||
if (cap_id == ext_cap_find_id) {
|
|
||||||
*p_offset = cap_offset;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the offset to the next New Capabilities item */
|
|
||||||
|
|
||||||
tmp_offset = cap_offset + (u8_t)0x01;
|
|
||||||
pci_config_in_byte(bus, device, function, (int)tmp_offset, &cap_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,400 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2009-2011, 2013-2014 Wind River Systems, Inc.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief PCI bus support
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This module implements the PCI H/W access functions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <kernel.h>
|
|
||||||
#include <arch/cpu.h>
|
|
||||||
|
|
||||||
#include <pci/pci_mgr.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <soc.h>
|
|
||||||
|
|
||||||
#if (PCI_CTRL_ADDR_REG == 0)
|
|
||||||
#error "PCI_CTRL_ADDR_REG cannot be zero"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (PCI_CTRL_DATA_REG == 0)
|
|
||||||
#error "PCI_CTRL_DATA_REG cannot be zero"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Read a PCI controller register
|
|
||||||
*
|
|
||||||
* @param reg PCI register to read
|
|
||||||
* @param data where to put the data
|
|
||||||
* @param size size of the data to read (8/16/32 bits)
|
|
||||||
*
|
|
||||||
* This routine reads the specified register from the PCI controller and
|
|
||||||
* places the data into the provided buffer.
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void pci_ctrl_read(u32_t reg, u32_t *data, u32_t size)
|
|
||||||
{
|
|
||||||
/* read based on the size requested */
|
|
||||||
|
|
||||||
switch (size) {
|
|
||||||
/* long (32 bits) */
|
|
||||||
case SYS_PCI_ACCESS_32BIT:
|
|
||||||
*data = sys_in32(reg);
|
|
||||||
break;
|
|
||||||
/* word (16 bits) */
|
|
||||||
case SYS_PCI_ACCESS_16BIT:
|
|
||||||
*data = sys_in16(reg);
|
|
||||||
break;
|
|
||||||
/* byte (8 bits) */
|
|
||||||
case SYS_PCI_ACCESS_8BIT:
|
|
||||||
*data = sys_in8(reg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Write a PCI controller register
|
|
||||||
*
|
|
||||||
* @param reg PCI register to write
|
|
||||||
* @param data data to write
|
|
||||||
* @param size size of the data to write (8/16/32 bits)
|
|
||||||
*
|
|
||||||
* This routine writes the provided data to the specified register in the PCI
|
|
||||||
* controller.
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void pci_ctrl_write(u32_t reg, u32_t data, u32_t size)
|
|
||||||
{
|
|
||||||
/* write based on the size requested */
|
|
||||||
|
|
||||||
switch (size) {
|
|
||||||
/* long (32 bits) */
|
|
||||||
case SYS_PCI_ACCESS_32BIT:
|
|
||||||
sys_out32(data, reg);
|
|
||||||
break;
|
|
||||||
/* word (16 bits) */
|
|
||||||
case SYS_PCI_ACCESS_16BIT:
|
|
||||||
sys_out16(data, reg);
|
|
||||||
break;
|
|
||||||
/* byte (8 bits) */
|
|
||||||
case SYS_PCI_ACCESS_8BIT:
|
|
||||||
sys_out8(data, reg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Read the PCI controller data register
|
|
||||||
*
|
|
||||||
* @param controller controller number
|
|
||||||
* @param offset is the offset within the data region
|
|
||||||
* @param data is the returned data
|
|
||||||
* @param size is the size of the data to read
|
|
||||||
*
|
|
||||||
* This routine reads the data register of the specified PCI controller.
|
|
||||||
*
|
|
||||||
* @return 0 or -1
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int pci_ctrl_data_read(u32_t controller, u32_t offset,
|
|
||||||
u32_t *data, u32_t size)
|
|
||||||
{
|
|
||||||
/* we only support one controller */
|
|
||||||
|
|
||||||
if (controller != DEFAULT_PCI_CONTROLLER) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_ctrl_read(PCI_CTRL_DATA_REG + offset, data, size);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Write the PCI controller data register
|
|
||||||
*
|
|
||||||
* @param controller the controller number
|
|
||||||
* @param offset is the offset within the address register
|
|
||||||
* @param data is the data to write
|
|
||||||
* @param size is the size of the data
|
|
||||||
*
|
|
||||||
* This routine writes the provided data to the data register of the
|
|
||||||
* specified PCI controller.
|
|
||||||
*
|
|
||||||
* @return 0 or -1
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int pci_ctrl_data_write(u32_t controller, u32_t offset,
|
|
||||||
u32_t data, u32_t size)
|
|
||||||
{
|
|
||||||
/* we only support one controller */
|
|
||||||
|
|
||||||
if (controller != DEFAULT_PCI_CONTROLLER) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_ctrl_write(PCI_CTRL_DATA_REG + offset, data, size);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Write the PCI controller address register
|
|
||||||
*
|
|
||||||
* @param controller is the controller number
|
|
||||||
* @param offset is the offset within the address register
|
|
||||||
* @param data is the data to write
|
|
||||||
* @param size is the size of the data
|
|
||||||
*
|
|
||||||
* This routine writes the provided data to the address register of the
|
|
||||||
* specified PCI controller.
|
|
||||||
*
|
|
||||||
* @return 0 or -1
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int pci_ctrl_addr_write(u32_t controller, u32_t offset,
|
|
||||||
u32_t data, u32_t size)
|
|
||||||
{
|
|
||||||
/* we only support one controller */
|
|
||||||
|
|
||||||
if (controller != DEFAULT_PCI_CONTROLLER) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_ctrl_write(PCI_CTRL_ADDR_REG + offset, data, size);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Read a PCI register from a device
|
|
||||||
*
|
|
||||||
* This routine reads data from a PCI device's configuration space. The
|
|
||||||
* device and register to read is specified by the address parameter ("addr")
|
|
||||||
* and must be set appropriately by the caller. The address is defined by
|
|
||||||
* the structure type pci_addr_t and contains the following members:
|
|
||||||
*
|
|
||||||
* bus: PCI bus number (0-255)
|
|
||||||
* device: PCI device number (0-31)
|
|
||||||
* func: device function number (0-7)
|
|
||||||
* reg: device 32-bit register number to read (0-63)
|
|
||||||
* offset: offset within 32-bit register to read (0-3)
|
|
||||||
*
|
|
||||||
* The size parameter specifies the number of bytes to read from the PCI
|
|
||||||
* configuration space, valid values are 1, 2, and 4 bytes. A 32-bit value
|
|
||||||
* is always returned but it will contain only the number of bytes specified
|
|
||||||
* by the size parameter.
|
|
||||||
*
|
|
||||||
* If multiple PCI controllers are present in the system, the controller id
|
|
||||||
* can be specified in the "controller" parameter. If only one controller
|
|
||||||
* is present, the id DEFAULT_PCI_CONTROLLER can be used to denote this
|
|
||||||
* controller.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* union pci_addr_reg addr;
|
|
||||||
* u32_t status;
|
|
||||||
*
|
|
||||||
* addr.field.bus = 0; /@ PCI bus zero @/
|
|
||||||
* addr.field.device = 1; /@ PCI device one @/
|
|
||||||
* addr.field.func = 0; /@ PCI function zero @/
|
|
||||||
* addr.field.reg = 4; /@ PCI register 4 @/
|
|
||||||
* addr.field.offset = 0; /@ PCI register offset @/
|
|
||||||
*
|
|
||||||
* pci_read (DEFAULT_PCI_CONTROLLER, addr, sizeof(u16_t), &status);
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* NOTE:
|
|
||||||
* Reading of PCI data must be performed as an atomic operation. It is up to
|
|
||||||
* the caller to enforce this.
|
|
||||||
*
|
|
||||||
* @param controller is the PCI controller number to use
|
|
||||||
* @param addr is the PCI address to read
|
|
||||||
* @param size is the size of the data in bytes
|
|
||||||
* @param data is a pointer to the data read from the device
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
void pci_read(u32_t controller, union pci_addr_reg addr,
|
|
||||||
u32_t size, u32_t *data)
|
|
||||||
{
|
|
||||||
u32_t access_size;
|
|
||||||
u32_t access_offset;
|
|
||||||
|
|
||||||
/* validate the access size */
|
|
||||||
|
|
||||||
switch (size) {
|
|
||||||
case 1:
|
|
||||||
access_size = SYS_PCI_ACCESS_8BIT;
|
|
||||||
access_offset = addr.field.offset;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
access_size = SYS_PCI_ACCESS_16BIT;
|
|
||||||
access_offset = addr.field.offset;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
default:
|
|
||||||
access_size = SYS_PCI_ACCESS_32BIT;
|
|
||||||
access_offset = 0U;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ensure enable has been set */
|
|
||||||
|
|
||||||
addr.field.enable = 1;
|
|
||||||
|
|
||||||
/* clear the offset for the address register */
|
|
||||||
|
|
||||||
addr.field.offset = 0;
|
|
||||||
|
|
||||||
/* read the data from the PCI controller */
|
|
||||||
|
|
||||||
pci_ctrl_addr_write(
|
|
||||||
controller, PCI_NO_OFFSET, addr.value, SYS_PCI_ACCESS_32BIT);
|
|
||||||
|
|
||||||
pci_ctrl_data_read(controller, access_offset, data, access_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Write a to a PCI register
|
|
||||||
*
|
|
||||||
* This routine writes data to a PCI device's configuration space. The
|
|
||||||
* device and register to write is specified by the address parameter ("addr")
|
|
||||||
* and must be set appropriately by the caller. The address is defined by
|
|
||||||
* the structure type pci_addr_t and contains the following members:
|
|
||||||
*
|
|
||||||
* bus: PCI bus number (0-255)
|
|
||||||
* device: PCI device number (0-31)
|
|
||||||
* func: device function number (0-7)
|
|
||||||
* reg: device register number to read (0-63)
|
|
||||||
* offset: offset within 32-bit register to write (0-3)
|
|
||||||
*
|
|
||||||
* The size parameter specifies the number of bytes to write to the PCI
|
|
||||||
* configuration space, valid values are 1, 2, and 4 bytes. A 32-bit value
|
|
||||||
* is always provided but only the number of bytes specified by the size
|
|
||||||
* parameter will be written to the device.
|
|
||||||
*
|
|
||||||
* If multiple PCI controllers are present in the system, the controller id
|
|
||||||
* can be specified in the "controller" parameter. If only one controller
|
|
||||||
* is present, the id DEFAULT_PCI_CONTROLLER can be used to denote this
|
|
||||||
* controller.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* pci_addr_t addr;
|
|
||||||
* u32_t bar0 = 0xE0000000;
|
|
||||||
*
|
|
||||||
* addr.field.bus = 0; /@ PCI bus zero @/
|
|
||||||
* addr.field.device = 1; /@ PCI device one @/
|
|
||||||
* addr.field.func = 0; /@ PCI function zero @/
|
|
||||||
* addr.field.reg = 16; /@ PCI register 16 @/
|
|
||||||
* addr.field.offset = 0; /@ PCI register offset @/
|
|
||||||
*
|
|
||||||
* pci_write (DEFAULT_PCI_CONTROLLER, addr, sizeof(u32_t), bar0);
|
|
||||||
*
|
|
||||||
* NOTE:
|
|
||||||
* Writing of PCI data must be performed as an atomic operation. It is up to
|
|
||||||
* the caller to enforce this.
|
|
||||||
*
|
|
||||||
* @param controller is the PCI controller to use
|
|
||||||
* @param addr is the PCI address to read
|
|
||||||
* @param size is the size in bytes to write
|
|
||||||
* @param data is the data to write
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
void pci_write(u32_t controller, union pci_addr_reg addr,
|
|
||||||
u32_t size, u32_t data)
|
|
||||||
{
|
|
||||||
u32_t access_size;
|
|
||||||
u32_t access_offset;
|
|
||||||
|
|
||||||
/* validate the access size */
|
|
||||||
|
|
||||||
switch (size) {
|
|
||||||
case 1:
|
|
||||||
access_size = SYS_PCI_ACCESS_8BIT;
|
|
||||||
access_offset = addr.field.offset;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
access_size = SYS_PCI_ACCESS_16BIT;
|
|
||||||
access_offset = addr.field.offset;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
default:
|
|
||||||
access_size = SYS_PCI_ACCESS_32BIT;
|
|
||||||
access_offset = 0U;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ensure enable has been set */
|
|
||||||
|
|
||||||
addr.field.enable = 1;
|
|
||||||
|
|
||||||
/* clear the offset for the address register */
|
|
||||||
|
|
||||||
addr.field.offset = 0;
|
|
||||||
|
|
||||||
/* write the data to the PCI controller */
|
|
||||||
|
|
||||||
pci_ctrl_addr_write(
|
|
||||||
controller, PCI_NO_OFFSET, addr.value, SYS_PCI_ACCESS_32BIT);
|
|
||||||
pci_ctrl_data_write(controller, access_offset, data, access_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @brief Get the PCI header for a device
|
|
||||||
*
|
|
||||||
* This routine reads the PCI header for the specified device and puts the
|
|
||||||
* result in the supplied header structure.
|
|
||||||
*
|
|
||||||
* @return N/A
|
|
||||||
*/
|
|
||||||
|
|
||||||
void pci_header_get(u32_t controller,
|
|
||||||
union pci_addr_reg pci_ctrl_addr,
|
|
||||||
union pci_dev *pci_dev_header)
|
|
||||||
{
|
|
||||||
u32_t i;
|
|
||||||
|
|
||||||
/* clear out the header */
|
|
||||||
|
|
||||||
(void)memset(pci_dev_header, 0, sizeof(*pci_dev_header));
|
|
||||||
|
|
||||||
/* fill in the PCI header from the device */
|
|
||||||
|
|
||||||
for (i = 0U; i < PCI_HEADER_WORDS; i++) {
|
|
||||||
pci_ctrl_addr.field.reg = i;
|
|
||||||
pci_read(controller,
|
|
||||||
pci_ctrl_addr,
|
|
||||||
sizeof(u32_t),
|
|
||||||
&pci_dev_header->words.word[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018 Intel Corporation
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <shell/shell.h>
|
|
||||||
#include <init.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <logging/log.h>
|
|
||||||
#include <pci/pci.h>
|
|
||||||
|
|
||||||
#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
|
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(lspci_shell);
|
|
||||||
|
|
||||||
static void list_devices(const struct shell *shell,
|
|
||||||
struct pci_dev_info *dev_info)
|
|
||||||
{
|
|
||||||
|
|
||||||
shell_fprintf(shell, SHELL_NORMAL,
|
|
||||||
"%x:%x.%x %X:%X class: 0x%X, %u, %s, "
|
|
||||||
"addrs: 0x%X-0x%X, IRQ %d\n",
|
|
||||||
dev_info->bus,
|
|
||||||
dev_info->dev,
|
|
||||||
dev_info->function,
|
|
||||||
dev_info->vendor_id,
|
|
||||||
dev_info->device_id,
|
|
||||||
dev_info->class_type,
|
|
||||||
dev_info->bar,
|
|
||||||
(dev_info->mem_type == BAR_SPACE_MEM) ? "MEM" : "I/O",
|
|
||||||
(u32_t)dev_info->addr,
|
|
||||||
(u32_t)(dev_info->addr + dev_info->size - 1),
|
|
||||||
dev_info->irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmd_lspci(const struct shell *shell, size_t argc, char **argv)
|
|
||||||
{
|
|
||||||
struct pci_dev_info info = {
|
|
||||||
.function = PCI_FUNCTION_ANY,
|
|
||||||
.bar = PCI_BAR_ANY,
|
|
||||||
};
|
|
||||||
|
|
||||||
pci_bus_scan_init();
|
|
||||||
|
|
||||||
while (pci_bus_scan(&info)) {
|
|
||||||
list_devices(shell, &info);
|
|
||||||
info.class_type = 0;
|
|
||||||
info.vendor_id = 0;
|
|
||||||
info.device_id = 0;
|
|
||||||
info.function = PCI_FUNCTION_ANY;
|
|
||||||
info.bar = PCI_BAR_ANY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHELL_CMD_REGISTER(lspci, NULL, "List PCI devices", cmd_lspci);
|
|
|
@ -1,78 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2013-2014 Wind River Systems, Inc.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* @brief PCI probe and information routines
|
|
||||||
*
|
|
||||||
* Module declares routines of PCI bus initialization and query
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ZEPHYR_INCLUDE_DRIVERS_PCI_PCI_H_
|
|
||||||
#define ZEPHYR_INCLUDE_DRIVERS_PCI_PCI_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BAR_SPACE_MEM 0
|
|
||||||
#define BAR_SPACE_IO 1
|
|
||||||
|
|
||||||
#define PCI_MAX_FUNCTIONS 8
|
|
||||||
#define PCI_FUNCTION_ANY PCI_MAX_FUNCTIONS
|
|
||||||
|
|
||||||
#define PCI_MAX_BARS 6
|
|
||||||
#define PCI_BAR_ANY PCI_MAX_BARS
|
|
||||||
|
|
||||||
/* PCI device information */
|
|
||||||
|
|
||||||
struct pci_dev_info {
|
|
||||||
u32_t addr; /* I/O or memory region address */
|
|
||||||
u32_t size; /* memory region size */
|
|
||||||
int irq;
|
|
||||||
|
|
||||||
u32_t bus:8;
|
|
||||||
u32_t dev:5;
|
|
||||||
u32_t function:4;
|
|
||||||
u32_t mem_type:1; /* memory type: BAR_SPACE_MEM/BAR_SPACE_IO */
|
|
||||||
u32_t class_type:8;
|
|
||||||
u32_t bar:3;
|
|
||||||
u32_t _reserved:3;
|
|
||||||
|
|
||||||
u16_t vendor_id;
|
|
||||||
u16_t device_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_ENUMERATION
|
|
||||||
extern void pci_bus_scan_init(void);
|
|
||||||
extern int pci_bus_scan(struct pci_dev_info *dev_info);
|
|
||||||
#else
|
|
||||||
#define pci_bus_scan_init(void) { ; }
|
|
||||||
static inline int pci_bus_scan(struct pci_dev_info *dev_info)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_PCI_ENUMERATION */
|
|
||||||
|
|
||||||
void pci_enable_regs(struct pci_dev_info *dev_info);
|
|
||||||
void pci_enable_bus_master(struct pci_dev_info *dev_info);
|
|
||||||
int pci_legacy_bridge_detect(struct pci_dev_info *dev_info);
|
|
||||||
void pci_legacy_bridge_configure(struct pci_dev_info *dev_info,
|
|
||||||
int io_block_num,
|
|
||||||
int pci_interrupt_pin,
|
|
||||||
int irq_number);
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_LOG_LEVEL_DBG
|
|
||||||
extern void pci_show(struct pci_dev_info *dev_info);
|
|
||||||
#else
|
|
||||||
#define pci_show(__unused__) { ; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_PCI_PCI_H_ */
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,7 +20,6 @@ config TEST
|
||||||
config TEST_SHELL
|
config TEST_SHELL
|
||||||
bool "Enable various shells for testing"
|
bool "Enable various shells for testing"
|
||||||
select GPIO_SHELL if GPIO
|
select GPIO_SHELL if GPIO
|
||||||
select PCI_SHELL if PCI
|
|
||||||
help
|
help
|
||||||
Enable various platform and driver related shells for testing.
|
Enable various platform and driver related shells for testing.
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13.1)
|
|
||||||
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
|
|
||||||
project(pci_enum)
|
|
||||||
|
|
||||||
FILE(GLOB app_sources src/*.c)
|
|
||||||
target_sources(app PRIVATE ${app_sources})
|
|
|
@ -1,3 +0,0 @@
|
||||||
CONFIG_PCI=y
|
|
||||||
CONFIG_PCI_ENUMERATION=y
|
|
||||||
CONFIG_ZTEST=y
|
|
|
@ -1,34 +0,0 @@
|
||||||
/* pci_enum.c - PCI Enumeration print-out application */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2015 Intel Corporation.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
#include <ztest.h>
|
|
||||||
#include <pci/pci.h>
|
|
||||||
|
|
||||||
static void pci_enumerate(void)
|
|
||||||
{
|
|
||||||
struct pci_dev_info info = {
|
|
||||||
.function = PCI_FUNCTION_ANY,
|
|
||||||
.bar = PCI_BAR_ANY,
|
|
||||||
};
|
|
||||||
|
|
||||||
pci_bus_scan_init();
|
|
||||||
|
|
||||||
while (pci_bus_scan(&info)) {
|
|
||||||
pci_show(&info);
|
|
||||||
info.class_type = 0;
|
|
||||||
info.vendor_id = 0;
|
|
||||||
info.device_id = 0;
|
|
||||||
info.function = PCI_FUNCTION_ANY;
|
|
||||||
info.bar = PCI_BAR_ANY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_main(void)
|
|
||||||
{
|
|
||||||
ztest_test_suite(pci_test, ztest_unit_test(pci_enumerate));
|
|
||||||
ztest_run_test_suite(pci_test);
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
tests:
|
|
||||||
peripheral.pci:
|
|
||||||
depends_on: pci
|
|
||||||
tags: drivers pci
|
|
Loading…
Add table
Add a link
Reference in a new issue