193a686eeSJean-Christophe PLAGNIOL-VILLARD /* 293a686eeSJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com> 393a686eeSJean-Christophe PLAGNIOL-VILLARD * Andreas Heppel <aheppel@sysgo.de> 493a686eeSJean-Christophe PLAGNIOL-VILLARD * 593a686eeSJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2002, 2003 693a686eeSJean-Christophe PLAGNIOL-VILLARD * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 793a686eeSJean-Christophe PLAGNIOL-VILLARD * 81a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 993a686eeSJean-Christophe PLAGNIOL-VILLARD */ 1093a686eeSJean-Christophe PLAGNIOL-VILLARD 1193a686eeSJean-Christophe PLAGNIOL-VILLARD /* 1293a686eeSJean-Christophe PLAGNIOL-VILLARD * PCI routines 1393a686eeSJean-Christophe PLAGNIOL-VILLARD */ 1493a686eeSJean-Christophe PLAGNIOL-VILLARD 1593a686eeSJean-Christophe PLAGNIOL-VILLARD #include <common.h> 1693a686eeSJean-Christophe PLAGNIOL-VILLARD 1793a686eeSJean-Christophe PLAGNIOL-VILLARD #include <command.h> 1893a686eeSJean-Christophe PLAGNIOL-VILLARD #include <asm/processor.h> 1993a686eeSJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h> 2093a686eeSJean-Christophe PLAGNIOL-VILLARD #include <pci.h> 2193a686eeSJean-Christophe PLAGNIOL-VILLARD 22*8f9052fdSBin Meng DECLARE_GLOBAL_DATA_PTR; 23*8f9052fdSBin Meng 2493a686eeSJean-Christophe PLAGNIOL-VILLARD #define PCI_HOSE_OP(rw, size, type) \ 2593a686eeSJean-Christophe PLAGNIOL-VILLARD int pci_hose_##rw##_config_##size(struct pci_controller *hose, \ 2693a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t dev, \ 2793a686eeSJean-Christophe PLAGNIOL-VILLARD int offset, type value) \ 2893a686eeSJean-Christophe PLAGNIOL-VILLARD { \ 2993a686eeSJean-Christophe PLAGNIOL-VILLARD return hose->rw##_##size(hose, dev, offset, value); \ 3093a686eeSJean-Christophe PLAGNIOL-VILLARD } 3193a686eeSJean-Christophe PLAGNIOL-VILLARD 3293a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_HOSE_OP(read, byte, u8 *) 3393a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_HOSE_OP(read, word, u16 *) 3493a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_HOSE_OP(read, dword, u32 *) 3593a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_HOSE_OP(write, byte, u8) 3693a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_HOSE_OP(write, word, u16) 3793a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_HOSE_OP(write, dword, u32) 3893a686eeSJean-Christophe PLAGNIOL-VILLARD 3993a686eeSJean-Christophe PLAGNIOL-VILLARD #define PCI_OP(rw, size, type, error_code) \ 4093a686eeSJean-Christophe PLAGNIOL-VILLARD int pci_##rw##_config_##size(pci_dev_t dev, int offset, type value) \ 4193a686eeSJean-Christophe PLAGNIOL-VILLARD { \ 4293a686eeSJean-Christophe PLAGNIOL-VILLARD struct pci_controller *hose = pci_bus_to_hose(PCI_BUS(dev)); \ 4393a686eeSJean-Christophe PLAGNIOL-VILLARD \ 4493a686eeSJean-Christophe PLAGNIOL-VILLARD if (!hose) \ 4593a686eeSJean-Christophe PLAGNIOL-VILLARD { \ 4693a686eeSJean-Christophe PLAGNIOL-VILLARD error_code; \ 4793a686eeSJean-Christophe PLAGNIOL-VILLARD return -1; \ 4893a686eeSJean-Christophe PLAGNIOL-VILLARD } \ 4993a686eeSJean-Christophe PLAGNIOL-VILLARD \ 5093a686eeSJean-Christophe PLAGNIOL-VILLARD return pci_hose_##rw##_config_##size(hose, dev, offset, value); \ 5193a686eeSJean-Christophe PLAGNIOL-VILLARD } 5293a686eeSJean-Christophe PLAGNIOL-VILLARD 5393a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_OP(read, byte, u8 *, *value = 0xff) 5493a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_OP(read, word, u16 *, *value = 0xffff) 5593a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_OP(read, dword, u32 *, *value = 0xffffffff) 5693a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_OP(write, byte, u8, ) 5793a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_OP(write, word, u16, ) 5893a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_OP(write, dword, u32, ) 5993a686eeSJean-Christophe PLAGNIOL-VILLARD 6093a686eeSJean-Christophe PLAGNIOL-VILLARD #define PCI_READ_VIA_DWORD_OP(size, type, off_mask) \ 6193a686eeSJean-Christophe PLAGNIOL-VILLARD int pci_hose_read_config_##size##_via_dword(struct pci_controller *hose,\ 6293a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t dev, \ 6393a686eeSJean-Christophe PLAGNIOL-VILLARD int offset, type val) \ 6493a686eeSJean-Christophe PLAGNIOL-VILLARD { \ 6593a686eeSJean-Christophe PLAGNIOL-VILLARD u32 val32; \ 6693a686eeSJean-Christophe PLAGNIOL-VILLARD \ 6793a686eeSJean-Christophe PLAGNIOL-VILLARD if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0) { \ 6893a686eeSJean-Christophe PLAGNIOL-VILLARD *val = -1; \ 6993a686eeSJean-Christophe PLAGNIOL-VILLARD return -1; \ 7093a686eeSJean-Christophe PLAGNIOL-VILLARD } \ 7193a686eeSJean-Christophe PLAGNIOL-VILLARD \ 7293a686eeSJean-Christophe PLAGNIOL-VILLARD *val = (val32 >> ((offset & (int)off_mask) * 8)); \ 7393a686eeSJean-Christophe PLAGNIOL-VILLARD \ 7493a686eeSJean-Christophe PLAGNIOL-VILLARD return 0; \ 7593a686eeSJean-Christophe PLAGNIOL-VILLARD } 7693a686eeSJean-Christophe PLAGNIOL-VILLARD 7793a686eeSJean-Christophe PLAGNIOL-VILLARD #define PCI_WRITE_VIA_DWORD_OP(size, type, off_mask, val_mask) \ 7893a686eeSJean-Christophe PLAGNIOL-VILLARD int pci_hose_write_config_##size##_via_dword(struct pci_controller *hose,\ 7993a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t dev, \ 8093a686eeSJean-Christophe PLAGNIOL-VILLARD int offset, type val) \ 8193a686eeSJean-Christophe PLAGNIOL-VILLARD { \ 8293a686eeSJean-Christophe PLAGNIOL-VILLARD u32 val32, mask, ldata, shift; \ 8393a686eeSJean-Christophe PLAGNIOL-VILLARD \ 8493a686eeSJean-Christophe PLAGNIOL-VILLARD if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0)\ 8593a686eeSJean-Christophe PLAGNIOL-VILLARD return -1; \ 8693a686eeSJean-Christophe PLAGNIOL-VILLARD \ 8793a686eeSJean-Christophe PLAGNIOL-VILLARD shift = ((offset & (int)off_mask) * 8); \ 8893a686eeSJean-Christophe PLAGNIOL-VILLARD ldata = (((unsigned long)val) & val_mask) << shift; \ 8993a686eeSJean-Christophe PLAGNIOL-VILLARD mask = val_mask << shift; \ 9093a686eeSJean-Christophe PLAGNIOL-VILLARD val32 = (val32 & ~mask) | ldata; \ 9193a686eeSJean-Christophe PLAGNIOL-VILLARD \ 9293a686eeSJean-Christophe PLAGNIOL-VILLARD if (pci_hose_write_config_dword(hose, dev, offset & 0xfc, val32) < 0)\ 9393a686eeSJean-Christophe PLAGNIOL-VILLARD return -1; \ 9493a686eeSJean-Christophe PLAGNIOL-VILLARD \ 9593a686eeSJean-Christophe PLAGNIOL-VILLARD return 0; \ 9693a686eeSJean-Christophe PLAGNIOL-VILLARD } 9793a686eeSJean-Christophe PLAGNIOL-VILLARD 9893a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_READ_VIA_DWORD_OP(byte, u8 *, 0x03) 9993a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_READ_VIA_DWORD_OP(word, u16 *, 0x02) 10093a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_WRITE_VIA_DWORD_OP(byte, u8, 0x03, 0x000000ff) 10193a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_WRITE_VIA_DWORD_OP(word, u16, 0x02, 0x0000ffff) 10293a686eeSJean-Christophe PLAGNIOL-VILLARD 1036e61fae4SBecky Bruce /* Get a virtual address associated with a BAR region */ 1046e61fae4SBecky Bruce void *pci_map_bar(pci_dev_t pdev, int bar, int flags) 1056e61fae4SBecky Bruce { 1066e61fae4SBecky Bruce pci_addr_t pci_bus_addr; 107cf5787f2SKumar Gala u32 bar_response; 1086e61fae4SBecky Bruce 1096e61fae4SBecky Bruce /* read BAR address */ 1106e61fae4SBecky Bruce pci_read_config_dword(pdev, bar, &bar_response); 111cf5787f2SKumar Gala pci_bus_addr = (pci_addr_t)(bar_response & ~0xf); 1126e61fae4SBecky Bruce 1136e61fae4SBecky Bruce /* 1146e61fae4SBecky Bruce * Pass "0" as the length argument to pci_bus_to_virt. The arg 1156e61fae4SBecky Bruce * isn't actualy used on any platform because u-boot assumes a static 1166e61fae4SBecky Bruce * linear mapping. In the future, this could read the BAR size 1176e61fae4SBecky Bruce * and pass that as the size if needed. 1186e61fae4SBecky Bruce */ 1196e61fae4SBecky Bruce return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE); 1206e61fae4SBecky Bruce } 1216e61fae4SBecky Bruce 12293a686eeSJean-Christophe PLAGNIOL-VILLARD /* 12393a686eeSJean-Christophe PLAGNIOL-VILLARD * 12493a686eeSJean-Christophe PLAGNIOL-VILLARD */ 12593a686eeSJean-Christophe PLAGNIOL-VILLARD 12696d61603SJohn Schmoller static struct pci_controller* hose_head; 12793a686eeSJean-Christophe PLAGNIOL-VILLARD 128*8f9052fdSBin Meng struct pci_controller *pci_get_hose_head(void) 129*8f9052fdSBin Meng { 130*8f9052fdSBin Meng if (gd->hose) 131*8f9052fdSBin Meng return gd->hose; 132*8f9052fdSBin Meng 133*8f9052fdSBin Meng return hose_head; 134*8f9052fdSBin Meng } 135*8f9052fdSBin Meng 13693a686eeSJean-Christophe PLAGNIOL-VILLARD void pci_register_hose(struct pci_controller* hose) 13793a686eeSJean-Christophe PLAGNIOL-VILLARD { 13893a686eeSJean-Christophe PLAGNIOL-VILLARD struct pci_controller **phose = &hose_head; 13993a686eeSJean-Christophe PLAGNIOL-VILLARD 14093a686eeSJean-Christophe PLAGNIOL-VILLARD while(*phose) 14193a686eeSJean-Christophe PLAGNIOL-VILLARD phose = &(*phose)->next; 14293a686eeSJean-Christophe PLAGNIOL-VILLARD 14393a686eeSJean-Christophe PLAGNIOL-VILLARD hose->next = NULL; 14493a686eeSJean-Christophe PLAGNIOL-VILLARD 14593a686eeSJean-Christophe PLAGNIOL-VILLARD *phose = hose; 14693a686eeSJean-Christophe PLAGNIOL-VILLARD } 14793a686eeSJean-Christophe PLAGNIOL-VILLARD 14893a686eeSJean-Christophe PLAGNIOL-VILLARD struct pci_controller *pci_bus_to_hose(int bus) 14993a686eeSJean-Christophe PLAGNIOL-VILLARD { 15093a686eeSJean-Christophe PLAGNIOL-VILLARD struct pci_controller *hose; 15193a686eeSJean-Christophe PLAGNIOL-VILLARD 152*8f9052fdSBin Meng for (hose = pci_get_hose_head(); hose; hose = hose->next) { 15393a686eeSJean-Christophe PLAGNIOL-VILLARD if (bus >= hose->first_busno && bus <= hose->last_busno) 15493a686eeSJean-Christophe PLAGNIOL-VILLARD return hose; 155cb2bf931SAndrew Sharp } 15693a686eeSJean-Christophe PLAGNIOL-VILLARD 15793a686eeSJean-Christophe PLAGNIOL-VILLARD printf("pci_bus_to_hose() failed\n"); 15893a686eeSJean-Christophe PLAGNIOL-VILLARD return NULL; 15993a686eeSJean-Christophe PLAGNIOL-VILLARD } 16093a686eeSJean-Christophe PLAGNIOL-VILLARD 1613a0e3c27SKumar Gala struct pci_controller *find_hose_by_cfg_addr(void *cfg_addr) 1623a0e3c27SKumar Gala { 1633a0e3c27SKumar Gala struct pci_controller *hose; 1643a0e3c27SKumar Gala 165*8f9052fdSBin Meng for (hose = pci_get_hose_head(); hose; hose = hose->next) { 1663a0e3c27SKumar Gala if (hose->cfg_addr == cfg_addr) 1673a0e3c27SKumar Gala return hose; 1683a0e3c27SKumar Gala } 1693a0e3c27SKumar Gala 1703a0e3c27SKumar Gala return NULL; 1713a0e3c27SKumar Gala } 1723a0e3c27SKumar Gala 173cc2a8c77SAnton Vorontsov int pci_last_busno(void) 174cc2a8c77SAnton Vorontsov { 175*8f9052fdSBin Meng struct pci_controller *hose = pci_get_hose_head(); 176cc2a8c77SAnton Vorontsov 177cc2a8c77SAnton Vorontsov if (!hose) 178cc2a8c77SAnton Vorontsov return -1; 179cc2a8c77SAnton Vorontsov 180cc2a8c77SAnton Vorontsov while (hose->next) 181cc2a8c77SAnton Vorontsov hose = hose->next; 182cc2a8c77SAnton Vorontsov 183cc2a8c77SAnton Vorontsov return hose->last_busno; 184cc2a8c77SAnton Vorontsov } 185cc2a8c77SAnton Vorontsov 18693a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t pci_find_devices(struct pci_device_id *ids, int index) 18793a686eeSJean-Christophe PLAGNIOL-VILLARD { 18893a686eeSJean-Christophe PLAGNIOL-VILLARD struct pci_controller * hose; 18993a686eeSJean-Christophe PLAGNIOL-VILLARD u16 vendor, device; 19093a686eeSJean-Christophe PLAGNIOL-VILLARD u8 header_type; 19193a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t bdf; 19293a686eeSJean-Christophe PLAGNIOL-VILLARD int i, bus, found_multi = 0; 19393a686eeSJean-Christophe PLAGNIOL-VILLARD 194*8f9052fdSBin Meng for (hose = pci_get_hose_head(); hose; hose = hose->next) { 1956d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE 19693a686eeSJean-Christophe PLAGNIOL-VILLARD for (bus = hose->last_busno; bus >= hose->first_busno; bus--) 19793a686eeSJean-Christophe PLAGNIOL-VILLARD #else 19893a686eeSJean-Christophe PLAGNIOL-VILLARD for (bus = hose->first_busno; bus <= hose->last_busno; bus++) 19993a686eeSJean-Christophe PLAGNIOL-VILLARD #endif 20093a686eeSJean-Christophe PLAGNIOL-VILLARD for (bdf = PCI_BDF(bus, 0, 0); 20193a686eeSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_ELPPC) || defined(CONFIG_PPMC7XX) 202cb2bf931SAndrew Sharp bdf < PCI_BDF(bus, PCI_MAX_PCI_DEVICES - 1, 203cb2bf931SAndrew Sharp PCI_MAX_PCI_FUNCTIONS - 1); 20493a686eeSJean-Christophe PLAGNIOL-VILLARD #else 20593a686eeSJean-Christophe PLAGNIOL-VILLARD bdf < PCI_BDF(bus + 1, 0, 0); 20693a686eeSJean-Christophe PLAGNIOL-VILLARD #endif 207cb2bf931SAndrew Sharp bdf += PCI_BDF(0, 0, 1)) { 2084efe52bfSThierry Reding if (pci_skip_dev(hose, bdf)) 2094efe52bfSThierry Reding continue; 2104efe52bfSThierry Reding 21193a686eeSJean-Christophe PLAGNIOL-VILLARD if (!PCI_FUNC(bdf)) { 21293a686eeSJean-Christophe PLAGNIOL-VILLARD pci_read_config_byte(bdf, 21393a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_HEADER_TYPE, 21493a686eeSJean-Christophe PLAGNIOL-VILLARD &header_type); 21593a686eeSJean-Christophe PLAGNIOL-VILLARD 21693a686eeSJean-Christophe PLAGNIOL-VILLARD found_multi = header_type & 0x80; 21793a686eeSJean-Christophe PLAGNIOL-VILLARD } else { 21893a686eeSJean-Christophe PLAGNIOL-VILLARD if (!found_multi) 21993a686eeSJean-Christophe PLAGNIOL-VILLARD continue; 22093a686eeSJean-Christophe PLAGNIOL-VILLARD } 22193a686eeSJean-Christophe PLAGNIOL-VILLARD 22293a686eeSJean-Christophe PLAGNIOL-VILLARD pci_read_config_word(bdf, 22393a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_VENDOR_ID, 22493a686eeSJean-Christophe PLAGNIOL-VILLARD &vendor); 22593a686eeSJean-Christophe PLAGNIOL-VILLARD pci_read_config_word(bdf, 22693a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_DEVICE_ID, 22793a686eeSJean-Christophe PLAGNIOL-VILLARD &device); 22893a686eeSJean-Christophe PLAGNIOL-VILLARD 229cb2bf931SAndrew Sharp for (i = 0; ids[i].vendor != 0; i++) { 23093a686eeSJean-Christophe PLAGNIOL-VILLARD if (vendor == ids[i].vendor && 231cb2bf931SAndrew Sharp device == ids[i].device) { 23293a686eeSJean-Christophe PLAGNIOL-VILLARD if (index <= 0) 23393a686eeSJean-Christophe PLAGNIOL-VILLARD return bdf; 23493a686eeSJean-Christophe PLAGNIOL-VILLARD 23593a686eeSJean-Christophe PLAGNIOL-VILLARD index--; 23693a686eeSJean-Christophe PLAGNIOL-VILLARD } 23793a686eeSJean-Christophe PLAGNIOL-VILLARD } 23893a686eeSJean-Christophe PLAGNIOL-VILLARD } 239cb2bf931SAndrew Sharp } 24093a686eeSJean-Christophe PLAGNIOL-VILLARD 241cb2bf931SAndrew Sharp return -1; 24293a686eeSJean-Christophe PLAGNIOL-VILLARD } 24393a686eeSJean-Christophe PLAGNIOL-VILLARD 24493a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index) 24593a686eeSJean-Christophe PLAGNIOL-VILLARD { 246*8f9052fdSBin Meng struct pci_device_id ids[2] = { {}, {0, 0} }; 24793a686eeSJean-Christophe PLAGNIOL-VILLARD 24893a686eeSJean-Christophe PLAGNIOL-VILLARD ids[0].vendor = vendor; 24993a686eeSJean-Christophe PLAGNIOL-VILLARD ids[0].device = device; 25093a686eeSJean-Christophe PLAGNIOL-VILLARD 25193a686eeSJean-Christophe PLAGNIOL-VILLARD return pci_find_devices(ids, index); 25293a686eeSJean-Christophe PLAGNIOL-VILLARD } 25393a686eeSJean-Christophe PLAGNIOL-VILLARD 25493a686eeSJean-Christophe PLAGNIOL-VILLARD /* 25593a686eeSJean-Christophe PLAGNIOL-VILLARD * 25693a686eeSJean-Christophe PLAGNIOL-VILLARD */ 25793a686eeSJean-Christophe PLAGNIOL-VILLARD 2582d43e873SKumar Gala int __pci_hose_phys_to_bus(struct pci_controller *hose, 25936f32675SBecky Bruce phys_addr_t phys_addr, 2602d43e873SKumar Gala unsigned long flags, 2612d43e873SKumar Gala unsigned long skip_mask, 2622d43e873SKumar Gala pci_addr_t *ba) 26393a686eeSJean-Christophe PLAGNIOL-VILLARD { 26493a686eeSJean-Christophe PLAGNIOL-VILLARD struct pci_region *res; 26530e76d5eSKumar Gala pci_addr_t bus_addr; 26693a686eeSJean-Christophe PLAGNIOL-VILLARD int i; 26793a686eeSJean-Christophe PLAGNIOL-VILLARD 26893a686eeSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < hose->region_count; i++) { 26993a686eeSJean-Christophe PLAGNIOL-VILLARD res = &hose->regions[i]; 27093a686eeSJean-Christophe PLAGNIOL-VILLARD 27193a686eeSJean-Christophe PLAGNIOL-VILLARD if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0) 27293a686eeSJean-Christophe PLAGNIOL-VILLARD continue; 27393a686eeSJean-Christophe PLAGNIOL-VILLARD 2742d43e873SKumar Gala if (res->flags & skip_mask) 2752d43e873SKumar Gala continue; 2762d43e873SKumar Gala 27793a686eeSJean-Christophe PLAGNIOL-VILLARD bus_addr = phys_addr - res->phys_start + res->bus_start; 27893a686eeSJean-Christophe PLAGNIOL-VILLARD 27993a686eeSJean-Christophe PLAGNIOL-VILLARD if (bus_addr >= res->bus_start && 28093a686eeSJean-Christophe PLAGNIOL-VILLARD bus_addr < res->bus_start + res->size) { 2812d43e873SKumar Gala *ba = bus_addr; 28293a686eeSJean-Christophe PLAGNIOL-VILLARD return 0; 28393a686eeSJean-Christophe PLAGNIOL-VILLARD } 2842d43e873SKumar Gala } 28593a686eeSJean-Christophe PLAGNIOL-VILLARD 2862d43e873SKumar Gala return 1; 2872d43e873SKumar Gala } 2882d43e873SKumar Gala 2892d43e873SKumar Gala pci_addr_t pci_hose_phys_to_bus (struct pci_controller *hose, 2902d43e873SKumar Gala phys_addr_t phys_addr, 29193a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned long flags) 29293a686eeSJean-Christophe PLAGNIOL-VILLARD { 2932d43e873SKumar Gala pci_addr_t bus_addr = 0; 2942d43e873SKumar Gala int ret; 2952d43e873SKumar Gala 2962d43e873SKumar Gala if (!hose) { 2972d43e873SKumar Gala puts("pci_hose_phys_to_bus: invalid hose\n"); 2982d43e873SKumar Gala return bus_addr; 2992d43e873SKumar Gala } 3002d43e873SKumar Gala 301cb2bf931SAndrew Sharp /* 302cb2bf931SAndrew Sharp * if PCI_REGION_MEM is set we do a two pass search with preference 303cb2bf931SAndrew Sharp * on matches that don't have PCI_REGION_SYS_MEMORY set 304cb2bf931SAndrew Sharp */ 3052d43e873SKumar Gala if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) { 3062d43e873SKumar Gala ret = __pci_hose_phys_to_bus(hose, phys_addr, 3072d43e873SKumar Gala flags, PCI_REGION_SYS_MEMORY, &bus_addr); 3082d43e873SKumar Gala if (!ret) 3092d43e873SKumar Gala return bus_addr; 3102d43e873SKumar Gala } 3112d43e873SKumar Gala 3122d43e873SKumar Gala ret = __pci_hose_phys_to_bus(hose, phys_addr, flags, 0, &bus_addr); 3132d43e873SKumar Gala 3142d43e873SKumar Gala if (ret) 3152d43e873SKumar Gala puts("pci_hose_phys_to_bus: invalid physical address\n"); 3162d43e873SKumar Gala 3172d43e873SKumar Gala return bus_addr; 3182d43e873SKumar Gala } 3192d43e873SKumar Gala 3202d43e873SKumar Gala int __pci_hose_bus_to_phys(struct pci_controller *hose, 3212d43e873SKumar Gala pci_addr_t bus_addr, 3222d43e873SKumar Gala unsigned long flags, 3232d43e873SKumar Gala unsigned long skip_mask, 3242d43e873SKumar Gala phys_addr_t *pa) 3252d43e873SKumar Gala { 32693a686eeSJean-Christophe PLAGNIOL-VILLARD struct pci_region *res; 32793a686eeSJean-Christophe PLAGNIOL-VILLARD int i; 32893a686eeSJean-Christophe PLAGNIOL-VILLARD 32993a686eeSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < hose->region_count; i++) { 33093a686eeSJean-Christophe PLAGNIOL-VILLARD res = &hose->regions[i]; 33193a686eeSJean-Christophe PLAGNIOL-VILLARD 33293a686eeSJean-Christophe PLAGNIOL-VILLARD if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0) 33393a686eeSJean-Christophe PLAGNIOL-VILLARD continue; 33493a686eeSJean-Christophe PLAGNIOL-VILLARD 3352d43e873SKumar Gala if (res->flags & skip_mask) 3362d43e873SKumar Gala continue; 3372d43e873SKumar Gala 33893a686eeSJean-Christophe PLAGNIOL-VILLARD if (bus_addr >= res->bus_start && 339d878c9a9SStephen Warren (bus_addr - res->bus_start) < res->size) { 3402d43e873SKumar Gala *pa = (bus_addr - res->bus_start + res->phys_start); 34193a686eeSJean-Christophe PLAGNIOL-VILLARD return 0; 34293a686eeSJean-Christophe PLAGNIOL-VILLARD } 3432d43e873SKumar Gala } 3442d43e873SKumar Gala 3452d43e873SKumar Gala return 1; 3462d43e873SKumar Gala } 3472d43e873SKumar Gala 3482d43e873SKumar Gala phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose, 3492d43e873SKumar Gala pci_addr_t bus_addr, 3502d43e873SKumar Gala unsigned long flags) 3512d43e873SKumar Gala { 3522d43e873SKumar Gala phys_addr_t phys_addr = 0; 3532d43e873SKumar Gala int ret; 3542d43e873SKumar Gala 3552d43e873SKumar Gala if (!hose) { 3562d43e873SKumar Gala puts("pci_hose_bus_to_phys: invalid hose\n"); 3572d43e873SKumar Gala return phys_addr; 3582d43e873SKumar Gala } 3592d43e873SKumar Gala 360cb2bf931SAndrew Sharp /* 361cb2bf931SAndrew Sharp * if PCI_REGION_MEM is set we do a two pass search with preference 362cb2bf931SAndrew Sharp * on matches that don't have PCI_REGION_SYS_MEMORY set 363cb2bf931SAndrew Sharp */ 3642d43e873SKumar Gala if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) { 3652d43e873SKumar Gala ret = __pci_hose_bus_to_phys(hose, bus_addr, 3662d43e873SKumar Gala flags, PCI_REGION_SYS_MEMORY, &phys_addr); 3672d43e873SKumar Gala if (!ret) 3682d43e873SKumar Gala return phys_addr; 3692d43e873SKumar Gala } 3702d43e873SKumar Gala 3712d43e873SKumar Gala ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr); 3722d43e873SKumar Gala 3732d43e873SKumar Gala if (ret) 3742d43e873SKumar Gala puts("pci_hose_bus_to_phys: invalid physical address\n"); 3752d43e873SKumar Gala 3762d43e873SKumar Gala return phys_addr; 3772d43e873SKumar Gala } 37893a686eeSJean-Christophe PLAGNIOL-VILLARD 379e8a552ebSSimon Glass void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum, 380e8a552ebSSimon Glass u32 addr_and_ctrl) 381e8a552ebSSimon Glass { 382e8a552ebSSimon Glass int bar; 383e8a552ebSSimon Glass 384e8a552ebSSimon Glass bar = PCI_BASE_ADDRESS_0 + barnum * 4; 385e8a552ebSSimon Glass pci_hose_write_config_dword(hose, dev, bar, addr_and_ctrl); 386e8a552ebSSimon Glass } 387e8a552ebSSimon Glass 388e8a552ebSSimon Glass u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum) 389e8a552ebSSimon Glass { 390e8a552ebSSimon Glass u32 addr; 391e8a552ebSSimon Glass int bar; 392e8a552ebSSimon Glass 393e8a552ebSSimon Glass bar = PCI_BASE_ADDRESS_0 + barnum * 4; 394e8a552ebSSimon Glass pci_hose_read_config_dword(hose, dev, bar, &addr); 395e8a552ebSSimon Glass if (addr & PCI_BASE_ADDRESS_SPACE_IO) 396e8a552ebSSimon Glass return addr & PCI_BASE_ADDRESS_IO_MASK; 397e8a552ebSSimon Glass else 398e8a552ebSSimon Glass return addr & PCI_BASE_ADDRESS_MEM_MASK; 399e8a552ebSSimon Glass } 40093a686eeSJean-Christophe PLAGNIOL-VILLARD 40193a686eeSJean-Christophe PLAGNIOL-VILLARD int pci_hose_config_device(struct pci_controller *hose, 40293a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t dev, 40393a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned long io, 40430e76d5eSKumar Gala pci_addr_t mem, 40593a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned long command) 40693a686eeSJean-Christophe PLAGNIOL-VILLARD { 407cf5787f2SKumar Gala u32 bar_response; 408af778c6dSAndrew Sharp unsigned int old_command; 40930e76d5eSKumar Gala pci_addr_t bar_value; 41030e76d5eSKumar Gala pci_size_t bar_size; 41193a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned char pin; 41293a686eeSJean-Christophe PLAGNIOL-VILLARD int bar, found_mem64; 41393a686eeSJean-Christophe PLAGNIOL-VILLARD 414cb2bf931SAndrew Sharp debug("PCI Config: I/O=0x%lx, Memory=0x%llx, Command=0x%lx\n", io, 415cb2bf931SAndrew Sharp (u64)mem, command); 41693a686eeSJean-Christophe PLAGNIOL-VILLARD 41793a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_dword(hose, dev, PCI_COMMAND, 0); 41893a686eeSJean-Christophe PLAGNIOL-VILLARD 419252b404dSWolfgang Denk for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar += 4) { 42093a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_dword(hose, dev, bar, 0xffffffff); 42193a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_dword(hose, dev, bar, &bar_response); 42293a686eeSJean-Christophe PLAGNIOL-VILLARD 42393a686eeSJean-Christophe PLAGNIOL-VILLARD if (!bar_response) 42493a686eeSJean-Christophe PLAGNIOL-VILLARD continue; 42593a686eeSJean-Christophe PLAGNIOL-VILLARD 42693a686eeSJean-Christophe PLAGNIOL-VILLARD found_mem64 = 0; 42793a686eeSJean-Christophe PLAGNIOL-VILLARD 42893a686eeSJean-Christophe PLAGNIOL-VILLARD /* Check the BAR type and set our address mask */ 42993a686eeSJean-Christophe PLAGNIOL-VILLARD if (bar_response & PCI_BASE_ADDRESS_SPACE) { 43093a686eeSJean-Christophe PLAGNIOL-VILLARD bar_size = ~(bar_response & PCI_BASE_ADDRESS_IO_MASK) + 1; 43193a686eeSJean-Christophe PLAGNIOL-VILLARD /* round up region base address to a multiple of size */ 43293a686eeSJean-Christophe PLAGNIOL-VILLARD io = ((io - 1) | (bar_size - 1)) + 1; 43393a686eeSJean-Christophe PLAGNIOL-VILLARD bar_value = io; 43493a686eeSJean-Christophe PLAGNIOL-VILLARD /* compute new region base address */ 43593a686eeSJean-Christophe PLAGNIOL-VILLARD io = io + bar_size; 43693a686eeSJean-Christophe PLAGNIOL-VILLARD } else { 43793a686eeSJean-Christophe PLAGNIOL-VILLARD if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == 43830e76d5eSKumar Gala PCI_BASE_ADDRESS_MEM_TYPE_64) { 43930e76d5eSKumar Gala u32 bar_response_upper; 44030e76d5eSKumar Gala u64 bar64; 441cb2bf931SAndrew Sharp pci_hose_write_config_dword(hose, dev, bar + 4, 442cb2bf931SAndrew Sharp 0xffffffff); 443cb2bf931SAndrew Sharp pci_hose_read_config_dword(hose, dev, bar + 4, 444cb2bf931SAndrew Sharp &bar_response_upper); 44593a686eeSJean-Christophe PLAGNIOL-VILLARD 44630e76d5eSKumar Gala bar64 = ((u64)bar_response_upper << 32) | bar_response; 44730e76d5eSKumar Gala 44830e76d5eSKumar Gala bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1; 44930e76d5eSKumar Gala found_mem64 = 1; 45030e76d5eSKumar Gala } else { 45130e76d5eSKumar Gala bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1); 45230e76d5eSKumar Gala } 45393a686eeSJean-Christophe PLAGNIOL-VILLARD 45493a686eeSJean-Christophe PLAGNIOL-VILLARD /* round up region base address to multiple of size */ 45593a686eeSJean-Christophe PLAGNIOL-VILLARD mem = ((mem - 1) | (bar_size - 1)) + 1; 45693a686eeSJean-Christophe PLAGNIOL-VILLARD bar_value = mem; 45793a686eeSJean-Christophe PLAGNIOL-VILLARD /* compute new region base address */ 45893a686eeSJean-Christophe PLAGNIOL-VILLARD mem = mem + bar_size; 45993a686eeSJean-Christophe PLAGNIOL-VILLARD } 46093a686eeSJean-Christophe PLAGNIOL-VILLARD 46193a686eeSJean-Christophe PLAGNIOL-VILLARD /* Write it out and update our limit */ 46230e76d5eSKumar Gala pci_hose_write_config_dword (hose, dev, bar, (u32)bar_value); 46393a686eeSJean-Christophe PLAGNIOL-VILLARD 46493a686eeSJean-Christophe PLAGNIOL-VILLARD if (found_mem64) { 46593a686eeSJean-Christophe PLAGNIOL-VILLARD bar += 4; 46630e76d5eSKumar Gala #ifdef CONFIG_SYS_PCI_64BIT 467cb2bf931SAndrew Sharp pci_hose_write_config_dword(hose, dev, bar, 468cb2bf931SAndrew Sharp (u32)(bar_value >> 32)); 46930e76d5eSKumar Gala #else 47093a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_dword(hose, dev, bar, 0x00000000); 47130e76d5eSKumar Gala #endif 47293a686eeSJean-Christophe PLAGNIOL-VILLARD } 47393a686eeSJean-Christophe PLAGNIOL-VILLARD } 47493a686eeSJean-Christophe PLAGNIOL-VILLARD 47593a686eeSJean-Christophe PLAGNIOL-VILLARD /* Configure Cache Line Size Register */ 47693a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08); 47793a686eeSJean-Christophe PLAGNIOL-VILLARD 47893a686eeSJean-Christophe PLAGNIOL-VILLARD /* Configure Latency Timer */ 47993a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80); 48093a686eeSJean-Christophe PLAGNIOL-VILLARD 48193a686eeSJean-Christophe PLAGNIOL-VILLARD /* Disable interrupt line, if device says it wants to use interrupts */ 48293a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_PIN, &pin); 48393a686eeSJean-Christophe PLAGNIOL-VILLARD if (pin != 0) { 48493a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, 0xff); 48593a686eeSJean-Christophe PLAGNIOL-VILLARD } 48693a686eeSJean-Christophe PLAGNIOL-VILLARD 48793a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &old_command); 48893a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_dword(hose, dev, PCI_COMMAND, 48993a686eeSJean-Christophe PLAGNIOL-VILLARD (old_command & 0xffff0000) | command); 49093a686eeSJean-Christophe PLAGNIOL-VILLARD 49193a686eeSJean-Christophe PLAGNIOL-VILLARD return 0; 49293a686eeSJean-Christophe PLAGNIOL-VILLARD } 49393a686eeSJean-Christophe PLAGNIOL-VILLARD 49493a686eeSJean-Christophe PLAGNIOL-VILLARD /* 49593a686eeSJean-Christophe PLAGNIOL-VILLARD * 49693a686eeSJean-Christophe PLAGNIOL-VILLARD */ 49793a686eeSJean-Christophe PLAGNIOL-VILLARD 49893a686eeSJean-Christophe PLAGNIOL-VILLARD struct pci_config_table *pci_find_config(struct pci_controller *hose, 49993a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned short class, 50093a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned int vendor, 50193a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned int device, 50293a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned int bus, 50393a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned int dev, 50493a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned int func) 50593a686eeSJean-Christophe PLAGNIOL-VILLARD { 50693a686eeSJean-Christophe PLAGNIOL-VILLARD struct pci_config_table *table; 50793a686eeSJean-Christophe PLAGNIOL-VILLARD 50893a686eeSJean-Christophe PLAGNIOL-VILLARD for (table = hose->config_table; table && table->vendor; table++) { 50993a686eeSJean-Christophe PLAGNIOL-VILLARD if ((table->vendor == PCI_ANY_ID || table->vendor == vendor) && 51093a686eeSJean-Christophe PLAGNIOL-VILLARD (table->device == PCI_ANY_ID || table->device == device) && 51193a686eeSJean-Christophe PLAGNIOL-VILLARD (table->class == PCI_ANY_ID || table->class == class) && 51293a686eeSJean-Christophe PLAGNIOL-VILLARD (table->bus == PCI_ANY_ID || table->bus == bus) && 51393a686eeSJean-Christophe PLAGNIOL-VILLARD (table->dev == PCI_ANY_ID || table->dev == dev) && 51493a686eeSJean-Christophe PLAGNIOL-VILLARD (table->func == PCI_ANY_ID || table->func == func)) { 51593a686eeSJean-Christophe PLAGNIOL-VILLARD return table; 51693a686eeSJean-Christophe PLAGNIOL-VILLARD } 51793a686eeSJean-Christophe PLAGNIOL-VILLARD } 51893a686eeSJean-Christophe PLAGNIOL-VILLARD 51993a686eeSJean-Christophe PLAGNIOL-VILLARD return NULL; 52093a686eeSJean-Christophe PLAGNIOL-VILLARD } 52193a686eeSJean-Christophe PLAGNIOL-VILLARD 52293a686eeSJean-Christophe PLAGNIOL-VILLARD void pci_cfgfunc_config_device(struct pci_controller *hose, 52393a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t dev, 52493a686eeSJean-Christophe PLAGNIOL-VILLARD struct pci_config_table *entry) 52593a686eeSJean-Christophe PLAGNIOL-VILLARD { 526cb2bf931SAndrew Sharp pci_hose_config_device(hose, dev, entry->priv[0], entry->priv[1], 527cb2bf931SAndrew Sharp entry->priv[2]); 52893a686eeSJean-Christophe PLAGNIOL-VILLARD } 52993a686eeSJean-Christophe PLAGNIOL-VILLARD 53093a686eeSJean-Christophe PLAGNIOL-VILLARD void pci_cfgfunc_do_nothing(struct pci_controller *hose, 53193a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t dev, struct pci_config_table *entry) 53293a686eeSJean-Christophe PLAGNIOL-VILLARD { 53393a686eeSJean-Christophe PLAGNIOL-VILLARD } 53493a686eeSJean-Christophe PLAGNIOL-VILLARD 53593a686eeSJean-Christophe PLAGNIOL-VILLARD /* 536cb2bf931SAndrew Sharp * HJF: Changed this to return int. I think this is required 53793a686eeSJean-Christophe PLAGNIOL-VILLARD * to get the correct result when scanning bridges 53893a686eeSJean-Christophe PLAGNIOL-VILLARD */ 53993a686eeSJean-Christophe PLAGNIOL-VILLARD extern int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev); 54093a686eeSJean-Christophe PLAGNIOL-VILLARD 541983eb9d1SPeter Tyser #if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI_SCAN_SHOW) 542983eb9d1SPeter Tyser const char * pci_class_str(u8 class) 543983eb9d1SPeter Tyser { 544983eb9d1SPeter Tyser switch (class) { 545983eb9d1SPeter Tyser case PCI_CLASS_NOT_DEFINED: 546983eb9d1SPeter Tyser return "Build before PCI Rev2.0"; 547983eb9d1SPeter Tyser break; 548983eb9d1SPeter Tyser case PCI_BASE_CLASS_STORAGE: 549983eb9d1SPeter Tyser return "Mass storage controller"; 550983eb9d1SPeter Tyser break; 551983eb9d1SPeter Tyser case PCI_BASE_CLASS_NETWORK: 552983eb9d1SPeter Tyser return "Network controller"; 553983eb9d1SPeter Tyser break; 554983eb9d1SPeter Tyser case PCI_BASE_CLASS_DISPLAY: 555983eb9d1SPeter Tyser return "Display controller"; 556983eb9d1SPeter Tyser break; 557983eb9d1SPeter Tyser case PCI_BASE_CLASS_MULTIMEDIA: 558983eb9d1SPeter Tyser return "Multimedia device"; 559983eb9d1SPeter Tyser break; 560983eb9d1SPeter Tyser case PCI_BASE_CLASS_MEMORY: 561983eb9d1SPeter Tyser return "Memory controller"; 562983eb9d1SPeter Tyser break; 563983eb9d1SPeter Tyser case PCI_BASE_CLASS_BRIDGE: 564983eb9d1SPeter Tyser return "Bridge device"; 565983eb9d1SPeter Tyser break; 566983eb9d1SPeter Tyser case PCI_BASE_CLASS_COMMUNICATION: 567983eb9d1SPeter Tyser return "Simple comm. controller"; 568983eb9d1SPeter Tyser break; 569983eb9d1SPeter Tyser case PCI_BASE_CLASS_SYSTEM: 570983eb9d1SPeter Tyser return "Base system peripheral"; 571983eb9d1SPeter Tyser break; 572983eb9d1SPeter Tyser case PCI_BASE_CLASS_INPUT: 573983eb9d1SPeter Tyser return "Input device"; 574983eb9d1SPeter Tyser break; 575983eb9d1SPeter Tyser case PCI_BASE_CLASS_DOCKING: 576983eb9d1SPeter Tyser return "Docking station"; 577983eb9d1SPeter Tyser break; 578983eb9d1SPeter Tyser case PCI_BASE_CLASS_PROCESSOR: 579983eb9d1SPeter Tyser return "Processor"; 580983eb9d1SPeter Tyser break; 581983eb9d1SPeter Tyser case PCI_BASE_CLASS_SERIAL: 582983eb9d1SPeter Tyser return "Serial bus controller"; 583983eb9d1SPeter Tyser break; 584983eb9d1SPeter Tyser case PCI_BASE_CLASS_INTELLIGENT: 585983eb9d1SPeter Tyser return "Intelligent controller"; 586983eb9d1SPeter Tyser break; 587983eb9d1SPeter Tyser case PCI_BASE_CLASS_SATELLITE: 588983eb9d1SPeter Tyser return "Satellite controller"; 589983eb9d1SPeter Tyser break; 590983eb9d1SPeter Tyser case PCI_BASE_CLASS_CRYPT: 591983eb9d1SPeter Tyser return "Cryptographic device"; 592983eb9d1SPeter Tyser break; 593983eb9d1SPeter Tyser case PCI_BASE_CLASS_SIGNAL_PROCESSING: 594983eb9d1SPeter Tyser return "DSP"; 595983eb9d1SPeter Tyser break; 596983eb9d1SPeter Tyser case PCI_CLASS_OTHERS: 597983eb9d1SPeter Tyser return "Does not fit any class"; 598983eb9d1SPeter Tyser break; 599983eb9d1SPeter Tyser default: 600983eb9d1SPeter Tyser return "???"; 601983eb9d1SPeter Tyser break; 602983eb9d1SPeter Tyser }; 603983eb9d1SPeter Tyser } 604983eb9d1SPeter Tyser #endif /* CONFIG_CMD_PCI || CONFIG_PCI_SCAN_SHOW */ 605983eb9d1SPeter Tyser 6067b19fd6dSJeroen Hofstee __weak int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev) 607dc1da42fSStefan Roese { 608dc1da42fSStefan Roese /* 609dc1da42fSStefan Roese * Check if pci device should be skipped in configuration 610dc1da42fSStefan Roese */ 611dc1da42fSStefan Roese if (dev == PCI_BDF(hose->first_busno, 0, 0)) { 612dc1da42fSStefan Roese #if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */ 613dc1da42fSStefan Roese /* 614dc1da42fSStefan Roese * Only skip configuration if "pciconfighost" is not set 615dc1da42fSStefan Roese */ 616dc1da42fSStefan Roese if (getenv("pciconfighost") == NULL) 617dc1da42fSStefan Roese return 1; 618dc1da42fSStefan Roese #else 619dc1da42fSStefan Roese return 1; 620dc1da42fSStefan Roese #endif 621dc1da42fSStefan Roese } 622dc1da42fSStefan Roese 623dc1da42fSStefan Roese return 0; 624dc1da42fSStefan Roese } 625dc1da42fSStefan Roese 626dc1da42fSStefan Roese #ifdef CONFIG_PCI_SCAN_SHOW 6277b19fd6dSJeroen Hofstee __weak int pci_print_dev(struct pci_controller *hose, pci_dev_t dev) 628dc1da42fSStefan Roese { 629dc1da42fSStefan Roese if (dev == PCI_BDF(hose->first_busno, 0, 0)) 630dc1da42fSStefan Roese return 0; 631dc1da42fSStefan Roese 632dc1da42fSStefan Roese return 1; 633dc1da42fSStefan Roese } 634dc1da42fSStefan Roese #endif /* CONFIG_PCI_SCAN_SHOW */ 635dc1da42fSStefan Roese 63693a686eeSJean-Christophe PLAGNIOL-VILLARD int pci_hose_scan_bus(struct pci_controller *hose, int bus) 63793a686eeSJean-Christophe PLAGNIOL-VILLARD { 63893a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned int sub_bus, found_multi = 0; 63993a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned short vendor, device, class; 64093a686eeSJean-Christophe PLAGNIOL-VILLARD unsigned char header_type; 64103992ac2SAndrew Sharp #ifndef CONFIG_PCI_PNP 64293a686eeSJean-Christophe PLAGNIOL-VILLARD struct pci_config_table *cfg; 64303992ac2SAndrew Sharp #endif 64493a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t dev; 645009884aeSPeter Tyser #ifdef CONFIG_PCI_SCAN_SHOW 646009884aeSPeter Tyser static int indent = 0; 647009884aeSPeter Tyser #endif 64893a686eeSJean-Christophe PLAGNIOL-VILLARD 64993a686eeSJean-Christophe PLAGNIOL-VILLARD sub_bus = bus; 65093a686eeSJean-Christophe PLAGNIOL-VILLARD 65193a686eeSJean-Christophe PLAGNIOL-VILLARD for (dev = PCI_BDF(bus,0,0); 652cb2bf931SAndrew Sharp dev < PCI_BDF(bus, PCI_MAX_PCI_DEVICES - 1, 653cb2bf931SAndrew Sharp PCI_MAX_PCI_FUNCTIONS - 1); 654dc1da42fSStefan Roese dev += PCI_BDF(0, 0, 1)) { 655dc1da42fSStefan Roese 656dc1da42fSStefan Roese if (pci_skip_dev(hose, dev)) 657dc1da42fSStefan Roese continue; 65893a686eeSJean-Christophe PLAGNIOL-VILLARD 65993a686eeSJean-Christophe PLAGNIOL-VILLARD if (PCI_FUNC(dev) && !found_multi) 66093a686eeSJean-Christophe PLAGNIOL-VILLARD continue; 66193a686eeSJean-Christophe PLAGNIOL-VILLARD 66293a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type); 66393a686eeSJean-Christophe PLAGNIOL-VILLARD 66493a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word(hose, dev, PCI_VENDOR_ID, &vendor); 66593a686eeSJean-Christophe PLAGNIOL-VILLARD 666983eb9d1SPeter Tyser if (vendor == 0xffff || vendor == 0x0000) 667983eb9d1SPeter Tyser continue; 66893a686eeSJean-Christophe PLAGNIOL-VILLARD 66993a686eeSJean-Christophe PLAGNIOL-VILLARD if (!PCI_FUNC(dev)) 67093a686eeSJean-Christophe PLAGNIOL-VILLARD found_multi = header_type & 0x80; 67193a686eeSJean-Christophe PLAGNIOL-VILLARD 67293a686eeSJean-Christophe PLAGNIOL-VILLARD debug("PCI Scan: Found Bus %d, Device %d, Function %d\n", 67393a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev)); 67493a686eeSJean-Christophe PLAGNIOL-VILLARD 67593a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word(hose, dev, PCI_DEVICE_ID, &device); 67693a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class); 67793a686eeSJean-Christophe PLAGNIOL-VILLARD 6780991866cSTim Harvey #ifdef CONFIG_PCI_FIXUP_DEV 6790991866cSTim Harvey board_pci_fixup_dev(hose, dev, vendor, device, class); 6800991866cSTim Harvey #endif 6810991866cSTim Harvey 682a38d216eSPeter Tyser #ifdef CONFIG_PCI_SCAN_SHOW 683009884aeSPeter Tyser indent++; 684009884aeSPeter Tyser 685009884aeSPeter Tyser /* Print leading space, including bus indentation */ 686009884aeSPeter Tyser printf("%*c", indent + 1, ' '); 687009884aeSPeter Tyser 688a38d216eSPeter Tyser if (pci_print_dev(hose, dev)) { 689009884aeSPeter Tyser printf("%02x:%02x.%-*x - %04x:%04x - %s\n", 690009884aeSPeter Tyser PCI_BUS(dev), PCI_DEV(dev), 6 - indent, PCI_FUNC(dev), 691a38d216eSPeter Tyser vendor, device, pci_class_str(class >> 8)); 692a38d216eSPeter Tyser } 693a38d216eSPeter Tyser #endif 694a38d216eSPeter Tyser 69503992ac2SAndrew Sharp #ifdef CONFIG_PCI_PNP 696b4141195SMasahiro Yamada sub_bus = max((unsigned int)pciauto_config_device(hose, dev), 697b4141195SMasahiro Yamada sub_bus); 69803992ac2SAndrew Sharp #else 69993a686eeSJean-Christophe PLAGNIOL-VILLARD cfg = pci_find_config(hose, class, vendor, device, 70093a686eeSJean-Christophe PLAGNIOL-VILLARD PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev)); 70193a686eeSJean-Christophe PLAGNIOL-VILLARD if (cfg) { 70293a686eeSJean-Christophe PLAGNIOL-VILLARD cfg->config_device(hose, dev, cfg); 703b4141195SMasahiro Yamada sub_bus = max(sub_bus, 704b4141195SMasahiro Yamada (unsigned int)hose->current_busno); 70593a686eeSJean-Christophe PLAGNIOL-VILLARD } 70603992ac2SAndrew Sharp #endif 707a38d216eSPeter Tyser 708009884aeSPeter Tyser #ifdef CONFIG_PCI_SCAN_SHOW 709009884aeSPeter Tyser indent--; 710009884aeSPeter Tyser #endif 711009884aeSPeter Tyser 71293a686eeSJean-Christophe PLAGNIOL-VILLARD if (hose->fixup_irq) 71393a686eeSJean-Christophe PLAGNIOL-VILLARD hose->fixup_irq(hose, dev); 71493a686eeSJean-Christophe PLAGNIOL-VILLARD } 71593a686eeSJean-Christophe PLAGNIOL-VILLARD 71693a686eeSJean-Christophe PLAGNIOL-VILLARD return sub_bus; 71793a686eeSJean-Christophe PLAGNIOL-VILLARD } 71893a686eeSJean-Christophe PLAGNIOL-VILLARD 71993a686eeSJean-Christophe PLAGNIOL-VILLARD int pci_hose_scan(struct pci_controller *hose) 72093a686eeSJean-Christophe PLAGNIOL-VILLARD { 7210da1fb03SAnatolij Gustschin #if defined(CONFIG_PCI_BOOTDELAY) 7220da1fb03SAnatolij Gustschin char *s; 7230da1fb03SAnatolij Gustschin int i; 7240da1fb03SAnatolij Gustschin 725*8f9052fdSBin Meng if (!gd->pcidelay_done) { 7260da1fb03SAnatolij Gustschin /* wait "pcidelay" ms (if defined)... */ 7270da1fb03SAnatolij Gustschin s = getenv("pcidelay"); 7280da1fb03SAnatolij Gustschin if (s) { 7290da1fb03SAnatolij Gustschin int val = simple_strtoul(s, NULL, 10); 7300da1fb03SAnatolij Gustschin for (i = 0; i < val; i++) 7310da1fb03SAnatolij Gustschin udelay(1000); 7320da1fb03SAnatolij Gustschin } 733*8f9052fdSBin Meng gd->pcidelay_done = 1; 7340da1fb03SAnatolij Gustschin } 7350da1fb03SAnatolij Gustschin #endif /* CONFIG_PCI_BOOTDELAY */ 7360da1fb03SAnatolij Gustschin 737cb2bf931SAndrew Sharp /* 738cb2bf931SAndrew Sharp * Start scan at current_busno. 73993a686eeSJean-Christophe PLAGNIOL-VILLARD * PCIe will start scan at first_busno+1. 74093a686eeSJean-Christophe PLAGNIOL-VILLARD */ 74193a686eeSJean-Christophe PLAGNIOL-VILLARD /* For legacy support, ensure current >= first */ 74293a686eeSJean-Christophe PLAGNIOL-VILLARD if (hose->first_busno > hose->current_busno) 74393a686eeSJean-Christophe PLAGNIOL-VILLARD hose->current_busno = hose->first_busno; 74493a686eeSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_PCI_PNP 74593a686eeSJean-Christophe PLAGNIOL-VILLARD pciauto_config_init(hose); 74693a686eeSJean-Christophe PLAGNIOL-VILLARD #endif 74793a686eeSJean-Christophe PLAGNIOL-VILLARD return pci_hose_scan_bus(hose, hose->current_busno); 74893a686eeSJean-Christophe PLAGNIOL-VILLARD } 74993a686eeSJean-Christophe PLAGNIOL-VILLARD 75093a686eeSJean-Christophe PLAGNIOL-VILLARD void pci_init(void) 75193a686eeSJean-Christophe PLAGNIOL-VILLARD { 75296d61603SJohn Schmoller hose_head = NULL; 75396d61603SJohn Schmoller 75493a686eeSJean-Christophe PLAGNIOL-VILLARD /* now call board specific pci_init()... */ 75593a686eeSJean-Christophe PLAGNIOL-VILLARD pci_init_board(); 75693a686eeSJean-Christophe PLAGNIOL-VILLARD } 757287df01eSZhao Qiang 758287df01eSZhao Qiang /* Returns the address of the requested capability structure within the 759287df01eSZhao Qiang * device's PCI configuration space or 0 in case the device does not 760287df01eSZhao Qiang * support it. 761287df01eSZhao Qiang * */ 762287df01eSZhao Qiang int pci_hose_find_capability(struct pci_controller *hose, pci_dev_t dev, 763287df01eSZhao Qiang int cap) 764287df01eSZhao Qiang { 765287df01eSZhao Qiang int pos; 766287df01eSZhao Qiang u8 hdr_type; 767287df01eSZhao Qiang 768287df01eSZhao Qiang pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &hdr_type); 769287df01eSZhao Qiang 770287df01eSZhao Qiang pos = pci_hose_find_cap_start(hose, dev, hdr_type & 0x7F); 771287df01eSZhao Qiang 772287df01eSZhao Qiang if (pos) 773287df01eSZhao Qiang pos = pci_find_cap(hose, dev, pos, cap); 774287df01eSZhao Qiang 775287df01eSZhao Qiang return pos; 776287df01eSZhao Qiang } 777287df01eSZhao Qiang 778287df01eSZhao Qiang /* Find the header pointer to the Capabilities*/ 779287df01eSZhao Qiang int pci_hose_find_cap_start(struct pci_controller *hose, pci_dev_t dev, 780287df01eSZhao Qiang u8 hdr_type) 781287df01eSZhao Qiang { 782287df01eSZhao Qiang u16 status; 783287df01eSZhao Qiang 784287df01eSZhao Qiang pci_hose_read_config_word(hose, dev, PCI_STATUS, &status); 785287df01eSZhao Qiang 786287df01eSZhao Qiang if (!(status & PCI_STATUS_CAP_LIST)) 787287df01eSZhao Qiang return 0; 788287df01eSZhao Qiang 789287df01eSZhao Qiang switch (hdr_type) { 790287df01eSZhao Qiang case PCI_HEADER_TYPE_NORMAL: 791287df01eSZhao Qiang case PCI_HEADER_TYPE_BRIDGE: 792287df01eSZhao Qiang return PCI_CAPABILITY_LIST; 793287df01eSZhao Qiang case PCI_HEADER_TYPE_CARDBUS: 794287df01eSZhao Qiang return PCI_CB_CAPABILITY_LIST; 795287df01eSZhao Qiang default: 796287df01eSZhao Qiang return 0; 797287df01eSZhao Qiang } 798287df01eSZhao Qiang } 799287df01eSZhao Qiang 800287df01eSZhao Qiang int pci_find_cap(struct pci_controller *hose, pci_dev_t dev, int pos, int cap) 801287df01eSZhao Qiang { 802287df01eSZhao Qiang int ttl = PCI_FIND_CAP_TTL; 803287df01eSZhao Qiang u8 id; 804287df01eSZhao Qiang u8 next_pos; 805287df01eSZhao Qiang 806287df01eSZhao Qiang while (ttl--) { 807287df01eSZhao Qiang pci_hose_read_config_byte(hose, dev, pos, &next_pos); 808287df01eSZhao Qiang if (next_pos < CAP_START_POS) 809287df01eSZhao Qiang break; 810287df01eSZhao Qiang next_pos &= ~3; 811287df01eSZhao Qiang pos = (int) next_pos; 812287df01eSZhao Qiang pci_hose_read_config_byte(hose, dev, 813287df01eSZhao Qiang pos + PCI_CAP_LIST_ID, &id); 814287df01eSZhao Qiang if (id == 0xff) 815287df01eSZhao Qiang break; 816287df01eSZhao Qiang if (id == cap) 817287df01eSZhao Qiang return pos; 818287df01eSZhao Qiang pos += PCI_CAP_LIST_NEXT; 819287df01eSZhao Qiang } 820287df01eSZhao Qiang return 0; 821287df01eSZhao Qiang } 822