1 /* 2 * (C) Copyright 2004 Tundra Semiconductor Corp. 3 * Alex Bounine <alexandreb@tundra.com> 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 /* 25 * PCI initialisation for the Tsi108 EMU board. 26 */ 27 28 #include <config.h> 29 30 #include <common.h> 31 #include <pci.h> 32 #include <asm/io.h> 33 #include <tsi108.h> 34 #if defined(CONFIG_OF_LIBFDT) 35 #include <libfdt.h> 36 #include <fdt_support.h> 37 #endif 38 39 struct pci_controller local_hose; 40 41 void tsi108_clear_pci_error (void) 42 { 43 u32 err_stat, err_addr, pci_stat; 44 45 /* 46 * Quietly clear errors signalled as result of PCI/X configuration read 47 * requests. 48 */ 49 /* Read PB Error Log Registers */ 50 err_stat = *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE + 51 TSI108_PB_REG_OFFSET + PB_ERRCS); 52 err_addr = *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE + 53 TSI108_PB_REG_OFFSET + PB_AERR); 54 if (err_stat & PB_ERRCS_ES) { 55 /* Clear PCI/X bus errors if applicable */ 56 if ((err_addr & 0xFF000000) == CONFIG_SYS_PCI_CFG_BASE) { 57 /* Clear error flag */ 58 *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + 59 TSI108_PB_REG_OFFSET + PB_ERRCS) = 60 PB_ERRCS_ES; 61 62 /* Clear read error reported in PB_ISR */ 63 *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + 64 TSI108_PB_REG_OFFSET + PB_ISR) = 65 PB_ISR_PBS_RD_ERR; 66 67 /* Clear errors reported by PCI CSR (Normally Master Abort) */ 68 pci_stat = *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE + 69 TSI108_PCI_REG_OFFSET + 70 PCI_CSR); 71 *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE + 72 TSI108_PCI_REG_OFFSET + PCI_CSR) = 73 pci_stat; 74 75 *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE + 76 TSI108_PCI_REG_OFFSET + 77 PCI_IRP_STAT) = PCI_IRP_STAT_P_CSR; 78 } 79 } 80 81 return; 82 } 83 84 unsigned int __get_pci_config_dword (u32 addr) 85 { 86 unsigned int retval; 87 88 __asm__ __volatile__ (" lwbrx %0,0,%1\n" 89 "1: eieio\n" 90 "2:\n" 91 ".section .fixup,\"ax\"\n" 92 "3: li %0,-1\n" 93 " b 2b\n" 94 ".section __ex_table,\"a\"\n" 95 " .align 2\n" 96 " .long 1b,3b\n" 97 ".section .text.__get_pci_config_dword" 98 : "=r"(retval) : "r"(addr)); 99 100 return (retval); 101 } 102 103 static int tsi108_read_config_dword (struct pci_controller *hose, 104 pci_dev_t dev, int offset, u32 * value) 105 { 106 dev &= (CONFIG_SYS_PCI_CFG_SIZE - 1); 107 dev |= (CONFIG_SYS_PCI_CFG_BASE | (offset & 0xfc)); 108 *value = __get_pci_config_dword(dev); 109 if (0xFFFFFFFF == *value) 110 tsi108_clear_pci_error (); 111 return 0; 112 } 113 114 static int tsi108_write_config_dword (struct pci_controller *hose, 115 pci_dev_t dev, int offset, u32 value) 116 { 117 dev &= (CONFIG_SYS_PCI_CFG_SIZE - 1); 118 dev |= (CONFIG_SYS_PCI_CFG_BASE | (offset & 0xfc)); 119 120 out_le32 ((volatile unsigned *)dev, value); 121 122 return 0; 123 } 124 125 void pci_init_board (void) 126 { 127 struct pci_controller *hose = (struct pci_controller *)&local_hose; 128 129 hose->first_busno = 0; 130 hose->last_busno = 0xff; 131 132 pci_set_region (hose->regions + 0, 133 CONFIG_SYS_PCI_MEMORY_BUS, 134 CONFIG_SYS_PCI_MEMORY_PHYS, 135 CONFIG_SYS_PCI_MEMORY_SIZE, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); 136 137 /* PCI memory space */ 138 pci_set_region (hose->regions + 1, 139 CONFIG_SYS_PCI_MEM_BUS, 140 CONFIG_SYS_PCI_MEM_PHYS, CONFIG_SYS_PCI_MEM_SIZE, PCI_REGION_MEM); 141 142 /* PCI I/O space */ 143 pci_set_region (hose->regions + 2, 144 CONFIG_SYS_PCI_IO_BUS, 145 CONFIG_SYS_PCI_IO_PHYS, CONFIG_SYS_PCI_IO_SIZE, PCI_REGION_IO); 146 147 hose->region_count = 3; 148 149 pci_set_ops (hose, 150 pci_hose_read_config_byte_via_dword, 151 pci_hose_read_config_word_via_dword, 152 tsi108_read_config_dword, 153 pci_hose_write_config_byte_via_dword, 154 pci_hose_write_config_word_via_dword, 155 tsi108_write_config_dword); 156 157 pci_register_hose (hose); 158 159 hose->last_busno = pci_hose_scan (hose); 160 161 debug ("Done PCI initialization\n"); 162 return; 163 } 164 165 #if defined(CONFIG_OF_LIBFDT) 166 void ft_pci_setup(void *blob, bd_t *bd) 167 { 168 int nodeoffset; 169 int tmp[2]; 170 const char *path; 171 172 nodeoffset = fdt_path_offset(blob, "/aliases"); 173 if (nodeoffset >= 0) { 174 path = fdt_getprop(blob, nodeoffset, "pci", NULL); 175 if (path) { 176 tmp[0] = cpu_to_be32(local_hose.first_busno); 177 tmp[1] = cpu_to_be32(local_hose.last_busno); 178 do_fixup_by_path(blob, path, "bus-range", 179 &tmp, sizeof(tmp), 1); 180 } 181 } 182 } 183 #endif /* CONFIG_OF_LIBFDT */ 184