/* 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);
}