1 /* 2 * Support for indirect PCI bridges. 3 * 4 * Copyright (C) 1998 Gabriel Paubert. 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 11 #if !defined(__I386__) 12 13 #include <asm/processor.h> 14 #include <asm/io.h> 15 #include <pci.h> 16 17 #define cfg_read(val, addr, type, op) *val = op((type)(addr)) 18 #define cfg_write(val, addr, type, op) op((type *)(addr), (val)) 19 20 #if defined(CONFIG_E500) || defined(CONFIG_MPC86xx) 21 #define INDIRECT_PCI_OP(rw, size, type, op, mask) \ 22 static int \ 23 indirect_##rw##_config_##size(struct pci_controller *hose, \ 24 pci_dev_t dev, int offset, type val) \ 25 { \ 26 u32 b, d,f; \ 27 b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ 28 b = b - hose->first_busno; \ 29 dev = PCI_BDF(b, d, f); \ 30 *(hose->cfg_addr) = dev | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000; \ 31 sync(); \ 32 cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ 33 return 0; \ 34 } 35 #elif defined(CONFIG_440GX) || defined(CONFIG_440GP) || defined(CONFIG_440SP) || \ 36 defined(CONFIG_440SPE) || defined(CONFIG_460EX) || defined(CONFIG_460GT) 37 #define INDIRECT_PCI_OP(rw, size, type, op, mask) \ 38 static int \ 39 indirect_##rw##_config_##size(struct pci_controller *hose, \ 40 pci_dev_t dev, int offset, type val) \ 41 { \ 42 u32 b, d,f; \ 43 b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ 44 b = b - hose->first_busno; \ 45 dev = PCI_BDF(b, d, f); \ 46 if (PCI_BUS(dev) > 0) \ 47 out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000001); \ 48 else \ 49 out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ 50 cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ 51 return 0; \ 52 } 53 #else 54 #define INDIRECT_PCI_OP(rw, size, type, op, mask) \ 55 static int \ 56 indirect_##rw##_config_##size(struct pci_controller *hose, \ 57 pci_dev_t dev, int offset, type val) \ 58 { \ 59 u32 b, d,f; \ 60 b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ 61 b = b - hose->first_busno; \ 62 dev = PCI_BDF(b, d, f); \ 63 out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ 64 cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ 65 return 0; \ 66 } 67 #endif 68 69 #define INDIRECT_PCI_OP_ERRATA6(rw, size, type, op, mask) \ 70 static int \ 71 indirect_##rw##_config_##size(struct pci_controller *hose, \ 72 pci_dev_t dev, int offset, type val) \ 73 { \ 74 unsigned int msr = mfmsr(); \ 75 mtmsr(msr & ~(MSR_EE | MSR_CE)); \ 76 out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ 77 cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ 78 out_le32(hose->cfg_addr, 0x00000000); \ 79 mtmsr(msr); \ 80 return 0; \ 81 } 82 83 INDIRECT_PCI_OP(read, byte, u8 *, in_8, 3) 84 INDIRECT_PCI_OP(read, word, u16 *, in_le16, 2) 85 INDIRECT_PCI_OP(read, dword, u32 *, in_le32, 0) 86 #ifdef CONFIG_405GP 87 INDIRECT_PCI_OP_ERRATA6(write, byte, u8, out_8, 3) 88 INDIRECT_PCI_OP_ERRATA6(write, word, u16, out_le16, 2) 89 INDIRECT_PCI_OP_ERRATA6(write, dword, u32, out_le32, 0) 90 #else 91 INDIRECT_PCI_OP(write, byte, u8, out_8, 3) 92 INDIRECT_PCI_OP(write, word, u16, out_le16, 2) 93 INDIRECT_PCI_OP(write, dword, u32, out_le32, 0) 94 #endif 95 96 void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) 97 { 98 pci_set_ops(hose, 99 indirect_read_config_byte, 100 indirect_read_config_word, 101 indirect_read_config_dword, 102 indirect_write_config_byte, 103 indirect_write_config_word, 104 indirect_write_config_dword); 105 106 hose->cfg_addr = (unsigned int *) cfg_addr; 107 hose->cfg_data = (unsigned char *) cfg_data; 108 } 109 110 #endif /* !__I386__ */ 111