forked from Imagelibrary/rtems
175 lines
5.1 KiB
C
175 lines
5.1 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
|
|
/* PCI (Static) Configuration Library
|
|
*
|
|
* COPYRIGHT (c) 2010 Cobham Gaisler AB.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* The Host Bridge bus must be declared by user. It contains the static
|
|
* configuration used to setup the devices/functions.
|
|
*/
|
|
|
|
/* Configure headers */
|
|
#define PCI_CFG_STATIC_LIB
|
|
|
|
#include <stdlib.h>
|
|
#include <pci.h>
|
|
#include <pci/access.h>
|
|
#include <pci/cfg.h>
|
|
|
|
#include "pci_internal.h"
|
|
|
|
#define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args)
|
|
#define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args)
|
|
#define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args)
|
|
#define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args)
|
|
#define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args)
|
|
#define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args)
|
|
|
|
/* Enumrate one bus if device is a bridge, and all it's subordinate buses */
|
|
static int pci_init_dev(struct pci_dev *dev, void *unused)
|
|
{
|
|
uint32_t tmp;
|
|
uint16_t tmp16, cmd;
|
|
struct pci_bus *bridge;
|
|
int maxbars, i, romofs;
|
|
pci_dev_t pcidev = dev->busdevfun;
|
|
struct pci_res *res;
|
|
|
|
/* Init Device */
|
|
|
|
/* Set command to reset values, it disables bus
|
|
* mastering and address responses.
|
|
*/
|
|
PCI_CFG_W16(pcidev, PCIR_COMMAND, 0);
|
|
|
|
/* Clear any already set status bits */
|
|
PCI_CFG_W16(pcidev, PCIR_STATUS, 0xf900);
|
|
|
|
/* Set latency timer to 64 */
|
|
PCI_CFG_W8(pcidev, PCIR_LATTIMER, 64);
|
|
|
|
/* Set System IRQ of PIN */
|
|
PCI_CFG_W8(pcidev, PCIR_INTLINE, dev->sysirq);
|
|
|
|
cmd = dev->command;
|
|
|
|
if ((dev->flags & PCI_DEV_BRIDGE) == 0) {
|
|
/* Disable Cardbus CIS Pointer */
|
|
PCI_CFG_W32(pcidev, PCIR_CIS, 0);
|
|
|
|
romofs = PCIR_BIOS;
|
|
maxbars = 6;
|
|
} else {
|
|
/* Init Bridge */
|
|
|
|
/* Configure bridge (no support for 64-bit) */
|
|
PCI_CFG_W32(pcidev, PCIR_PMBASEH_1, 0);
|
|
PCI_CFG_W32(pcidev, PCIR_PMLIMITH_1, 0);
|
|
|
|
bridge = (struct pci_bus *)dev;
|
|
tmp = (64 << 24) | (bridge->sord << 16) |
|
|
(bridge->num << 8) | bridge->pri;
|
|
PCI_CFG_W32(pcidev, PCIR_PRIBUS_1, tmp);
|
|
|
|
/*** Setup I/O Bridge Window ***/
|
|
res = &dev->resources[BRIDGE_RES_IO];
|
|
if (res->size > 0) {
|
|
tmp16 = ((res->end-1) & 0x0000f000) |
|
|
((res->start & 0x0000f000) >> 8);
|
|
tmp = ((res->end-1) & 0xffff0000) | (res->start >> 16);
|
|
cmd |= PCIM_CMD_PORTEN;
|
|
} else {
|
|
tmp16 = 0x00ff;
|
|
tmp = 0;
|
|
}
|
|
/* I/O Limit and Base */
|
|
PCI_CFG_W16(pcidev, PCIR_IOBASEL_1, tmp16);
|
|
PCI_CFG_W32(pcidev, PCIR_IOBASEH_1, tmp);
|
|
|
|
/*** Setup MEMIO Bridge Window ***/
|
|
res = &dev->resources[BRIDGE_RES_MEMIO];
|
|
if (res->size > 0) {
|
|
tmp = ((res->end-1) & 0xffff0000) |
|
|
(res->start >> 16);
|
|
cmd |= PCIM_CMD_MEMEN;
|
|
} else {
|
|
tmp = 0x0000ffff;
|
|
}
|
|
/* MEMIO Limit and Base */
|
|
PCI_CFG_W32(pcidev, PCIR_MEMBASE_1, tmp);
|
|
|
|
/*** Setup MEM Bridge Window ***/
|
|
res = &dev->resources[BRIDGE_RES_MEM];
|
|
if (res->size > 0) {
|
|
tmp = ((res->end-1) & 0xffff0000) |
|
|
(res->start >> 16);
|
|
cmd |= PCIM_CMD_MEMEN;
|
|
} else {
|
|
tmp = 0x0000ffff;
|
|
}
|
|
/* MEM Limit and Base */
|
|
PCI_CFG_W32(pcidev, PCIR_PMBASEL_1, tmp);
|
|
/* 64-bit space not supported */
|
|
PCI_CFG_W32(pcidev, PCIR_PMBASEH_1, 0);
|
|
PCI_CFG_W32(pcidev, PCIR_PMLIMITH_1, 0);
|
|
|
|
cmd |= PCIM_CMD_BUSMASTEREN;
|
|
romofs = PCIR_BIOS_1;
|
|
maxbars = 2;
|
|
}
|
|
|
|
/* Init BARs */
|
|
for (i = 0; i < maxbars; i++) {
|
|
res = &dev->resources[i];
|
|
if (res->flags & PCI_RES_TYPE_MASK) {
|
|
PCI_CFG_W32(pcidev, PCIR_BAR(0) + 4*i,
|
|
res->start);
|
|
if ((res->flags & PCI_RES_TYPE_MASK) == PCI_RES_IO)
|
|
cmd |= PCIM_CMD_PORTEN;
|
|
else
|
|
cmd |= PCIM_CMD_MEMEN;
|
|
}
|
|
}
|
|
res = &dev->resources[DEV_RES_ROM];
|
|
if (res->flags & PCI_RES_TYPE_MASK) {
|
|
PCI_CFG_W32(pcidev, romofs, res->start|PCIM_BIOS_ENABLE);
|
|
cmd |= PCIM_CMD_MEMEN;
|
|
}
|
|
PCI_CFG_W16(pcidev, PCIR_COMMAND, cmd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Assume that user has defined static setup array in pci_hb */
|
|
int pci_config_static(void)
|
|
{
|
|
pci_bus_cnt = pci_hb.sord + 1;
|
|
pci_system_type = PCI_SYSTEM_HOST;
|
|
|
|
/* Init all PCI devices according to depth-first search algorithm */
|
|
return pci_for_each_dev(pci_init_dev, NULL);
|
|
}
|