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