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_MPC8260) 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 out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ 31 sync(); \ 32 cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ 33 return 0; \ 34 } 35 #elif defined(CONFIG_E500) || defined(CONFIG_MPC86xx) 36 #define INDIRECT_PCI_OP(rw, size, type, op, mask) \ 37 static int \ 38 indirect_##rw##_config_##size(struct pci_controller *hose, \ 39 pci_dev_t dev, int offset, type val) \ 40 { \ 41 u32 b, d,f; \ 42 b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ 43 b = b - hose->first_busno; \ 44 dev = PCI_BDF(b, d, f); \ 45 *(hose->cfg_addr) = dev | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000; \ 46 sync(); \ 47 cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ 48 return 0; \ 49 } 50 #elif defined(CONFIG_440GX) || defined(CONFIG_440GP) || defined(CONFIG_440SP) || \ 51 defined(CONFIG_440SPE) || defined(CONFIG_460EX) || defined(CONFIG_460GT) 52 #define INDIRECT_PCI_OP(rw, size, type, op, mask) \ 53 static int \ 54 indirect_##rw##_config_##size(struct pci_controller *hose, \ 55 pci_dev_t dev, int offset, type val) \ 56 { \ 57 u32 b, d,f; \ 58 b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ 59 b = b - hose->first_busno; \ 60 dev = PCI_BDF(b, d, f); \ 61 if (PCI_BUS(dev) > 0) \ 62 out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000001); \ 63 else \ 64 out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ 65 cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ 66 return 0; \ 67 } 68 #else 69 #define INDIRECT_PCI_OP(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 u32 b, d,f; \ 75 b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ 76 b = b - hose->first_busno; \ 77 dev = PCI_BDF(b, d, f); \ 78 out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ 79 cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ 80 return 0; \ 81 } 82 #endif 83 84 #define INDIRECT_PCI_OP_ERRATA6(rw, size, type, op, mask) \ 85 static int \ 86 indirect_##rw##_config_##size(struct pci_controller *hose, \ 87 pci_dev_t dev, int offset, type val) \ 88 { \ 89 unsigned int msr = mfmsr(); \ 90 mtmsr(msr & ~(MSR_EE | MSR_CE)); \ 91 out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ 92 cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ 93 out_le32(hose->cfg_addr, 0x00000000); \ 94 mtmsr(msr); \ 95 return 0; \ 96 } 97 98 INDIRECT_PCI_OP(read, byte, u8 *, in_8, 3) 99 INDIRECT_PCI_OP(read, word, u16 *, in_le16, 2) 100 INDIRECT_PCI_OP(read, dword, u32 *, in_le32, 0) 101 #ifdef CONFIG_405GP 102 INDIRECT_PCI_OP_ERRATA6(write, byte, u8, out_8, 3) 103 INDIRECT_PCI_OP_ERRATA6(write, word, u16, out_le16, 2) 104 INDIRECT_PCI_OP_ERRATA6(write, dword, u32, out_le32, 0) 105 #else 106 INDIRECT_PCI_OP(write, byte, u8, out_8, 3) 107 INDIRECT_PCI_OP(write, word, u16, out_le16, 2) 108 INDIRECT_PCI_OP(write, dword, u32, out_le32, 0) 109 #endif 110 111 void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) 112 { 113 pci_set_ops(hose, 114 indirect_read_config_byte, 115 indirect_read_config_word, 116 indirect_read_config_dword, 117 indirect_write_config_byte, 118 indirect_write_config_word, 119 indirect_write_config_dword); 120 121 hose->cfg_addr = (unsigned int *) cfg_addr; 122 hose->cfg_data = (unsigned char *) cfg_data; 123 } 124 125 #endif /* !__I386__ */ 126