1d188b18fSSimon Glass /* 2d188b18fSSimon Glass * Copyright (c) 2011 The Chromium OS Authors. 3d188b18fSSimon Glass * (C) Copyright 2008,2009 4d188b18fSSimon Glass * Graeme Russ, <graeme.russ@gmail.com> 5d188b18fSSimon Glass * 6d188b18fSSimon Glass * (C) Copyright 2002 7d188b18fSSimon Glass * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> 8d188b18fSSimon Glass * 9d188b18fSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 10d188b18fSSimon Glass */ 11d188b18fSSimon Glass 12d188b18fSSimon Glass #include <common.h> 13a219daeaSSimon Glass #include <dm.h> 147430f108SSimon Glass #include <errno.h> 157430f108SSimon Glass #include <malloc.h> 16d188b18fSSimon Glass #include <pci.h> 17a219daeaSSimon Glass #include <asm/io.h> 18d188b18fSSimon Glass #include <asm/pci.h> 19d188b18fSSimon Glass 204722c035SBin Meng DECLARE_GLOBAL_DATA_PTR; 214722c035SBin Meng 226fb3b72eSSimon Glass static struct pci_controller *get_hose(void) 236fb3b72eSSimon Glass { 248f9052fdSBin Meng if (gd->hose) 258f9052fdSBin Meng return gd->hose; 266fb3b72eSSimon Glass 276fb3b72eSSimon Glass return pci_bus_to_hose(0); 286fb3b72eSSimon Glass } 296fb3b72eSSimon Glass 3031f57c28SSimon Glass unsigned int x86_pci_read_config8(pci_dev_t dev, unsigned where) 316fb3b72eSSimon Glass { 326fb3b72eSSimon Glass uint8_t value; 336fb3b72eSSimon Glass 34052e34b3SSimon Glass if (pci_hose_read_config_byte(get_hose(), dev, where, &value)) 35052e34b3SSimon Glass return -1U; 366fb3b72eSSimon Glass 376fb3b72eSSimon Glass return value; 386fb3b72eSSimon Glass } 396fb3b72eSSimon Glass 4031f57c28SSimon Glass unsigned int x86_pci_read_config16(pci_dev_t dev, unsigned where) 416fb3b72eSSimon Glass { 426fb3b72eSSimon Glass uint16_t value; 436fb3b72eSSimon Glass 44052e34b3SSimon Glass if (pci_hose_read_config_word(get_hose(), dev, where, &value)) 45052e34b3SSimon Glass return -1U; 466fb3b72eSSimon Glass 476fb3b72eSSimon Glass return value; 486fb3b72eSSimon Glass } 496fb3b72eSSimon Glass 5031f57c28SSimon Glass unsigned int x86_pci_read_config32(pci_dev_t dev, unsigned where) 516fb3b72eSSimon Glass { 526fb3b72eSSimon Glass uint32_t value; 536fb3b72eSSimon Glass 54052e34b3SSimon Glass if (pci_hose_read_config_dword(get_hose(), dev, where, &value)) 55052e34b3SSimon Glass return -1U; 566fb3b72eSSimon Glass 576fb3b72eSSimon Glass return value; 586fb3b72eSSimon Glass } 596fb3b72eSSimon Glass 6031f57c28SSimon Glass void x86_pci_write_config8(pci_dev_t dev, unsigned where, unsigned value) 616fb3b72eSSimon Glass { 626fb3b72eSSimon Glass pci_hose_write_config_byte(get_hose(), dev, where, value); 636fb3b72eSSimon Glass } 646fb3b72eSSimon Glass 6531f57c28SSimon Glass void x86_pci_write_config16(pci_dev_t dev, unsigned where, unsigned value) 666fb3b72eSSimon Glass { 676fb3b72eSSimon Glass pci_hose_write_config_word(get_hose(), dev, where, value); 686fb3b72eSSimon Glass } 696fb3b72eSSimon Glass 7031f57c28SSimon Glass void x86_pci_write_config32(pci_dev_t dev, unsigned where, unsigned value) 716fb3b72eSSimon Glass { 726fb3b72eSSimon Glass pci_hose_write_config_dword(get_hose(), dev, where, value); 736fb3b72eSSimon Glass } 74a219daeaSSimon Glass 75a219daeaSSimon Glass int pci_x86_read_config(struct udevice *bus, pci_dev_t bdf, uint offset, 76a219daeaSSimon Glass ulong *valuep, enum pci_size_t size) 77a219daeaSSimon Glass { 78a219daeaSSimon Glass outl(bdf | (offset & 0xfc) | PCI_CFG_EN, PCI_REG_ADDR); 79a219daeaSSimon Glass switch (size) { 80a219daeaSSimon Glass case PCI_SIZE_8: 81a219daeaSSimon Glass *valuep = inb(PCI_REG_DATA + (offset & 3)); 82a219daeaSSimon Glass break; 83a219daeaSSimon Glass case PCI_SIZE_16: 84a219daeaSSimon Glass *valuep = inw(PCI_REG_DATA + (offset & 2)); 85a219daeaSSimon Glass break; 86a219daeaSSimon Glass case PCI_SIZE_32: 87a219daeaSSimon Glass *valuep = inl(PCI_REG_DATA); 88a219daeaSSimon Glass break; 89a219daeaSSimon Glass } 90a219daeaSSimon Glass 91a219daeaSSimon Glass return 0; 92a219daeaSSimon Glass } 93a219daeaSSimon Glass 94a219daeaSSimon Glass int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, 95a219daeaSSimon Glass ulong value, enum pci_size_t size) 96a219daeaSSimon Glass { 97a219daeaSSimon Glass outl(bdf | (offset & 0xfc) | PCI_CFG_EN, PCI_REG_ADDR); 98a219daeaSSimon Glass switch (size) { 99a219daeaSSimon Glass case PCI_SIZE_8: 100a219daeaSSimon Glass outb(value, PCI_REG_DATA + (offset & 3)); 101a219daeaSSimon Glass break; 102a219daeaSSimon Glass case PCI_SIZE_16: 103a219daeaSSimon Glass outw(value, PCI_REG_DATA + (offset & 2)); 104a219daeaSSimon Glass break; 105a219daeaSSimon Glass case PCI_SIZE_32: 106a219daeaSSimon Glass outl(value, PCI_REG_DATA); 107a219daeaSSimon Glass break; 108a219daeaSSimon Glass } 109a219daeaSSimon Glass 110a219daeaSSimon Glass return 0; 111a219daeaSSimon Glass } 112e3e7fa2cSBin Meng 11331a2dc69SBin Meng void pci_assign_irqs(int bus, int device, u8 irq[4]) 114e3e7fa2cSBin Meng { 115e3e7fa2cSBin Meng pci_dev_t bdf; 11631a2dc69SBin Meng int func; 11731a2dc69SBin Meng u16 vendor; 118e3e7fa2cSBin Meng u8 pin, line; 119e3e7fa2cSBin Meng 12031a2dc69SBin Meng for (func = 0; func < 8; func++) { 121e3e7fa2cSBin Meng bdf = PCI_BDF(bus, device, func); 122*58316f9bSBin Meng pci_read_config16(bdf, PCI_VENDOR_ID, &vendor); 12331a2dc69SBin Meng if (vendor == 0xffff || vendor == 0x0000) 12431a2dc69SBin Meng continue; 125e3e7fa2cSBin Meng 126*58316f9bSBin Meng pci_read_config8(bdf, PCI_INTERRUPT_PIN, &pin); 127e3e7fa2cSBin Meng 128e3e7fa2cSBin Meng /* PCI spec says all values except 1..4 are reserved */ 129e3e7fa2cSBin Meng if ((pin < 1) || (pin > 4)) 13031a2dc69SBin Meng continue; 131e3e7fa2cSBin Meng 132e3e7fa2cSBin Meng line = irq[pin - 1]; 1336fc0e8a1SBin Meng if (!line) 1346fc0e8a1SBin Meng continue; 135e3e7fa2cSBin Meng 136e3e7fa2cSBin Meng debug("Assigning IRQ %d to PCI device %d.%x.%d (INT%c)\n", 137e3e7fa2cSBin Meng line, bus, device, func, 'A' + pin - 1); 138e3e7fa2cSBin Meng 139*58316f9bSBin Meng pci_write_config8(bdf, PCI_INTERRUPT_LINE, line); 140e3e7fa2cSBin Meng } 14131a2dc69SBin Meng } 142