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 ".text":"=r"(retval):"r"(addr)); 98 99 return (retval); 100 } 101 102 static int tsi108_read_config_dword (struct pci_controller *hose, 103 pci_dev_t dev, int offset, u32 * value) 104 { 105 dev &= (CONFIG_SYS_PCI_CFG_SIZE - 1); 106 dev |= (CONFIG_SYS_PCI_CFG_BASE | (offset & 0xfc)); 107 *value = __get_pci_config_dword(dev); 108 if (0xFFFFFFFF == *value) 109 tsi108_clear_pci_error (); 110 return 0; 111 } 112 113 static int tsi108_write_config_dword (struct pci_controller *hose, 114 pci_dev_t dev, int offset, u32 value) 115 { 116 dev &= (CONFIG_SYS_PCI_CFG_SIZE - 1); 117 dev |= (CONFIG_SYS_PCI_CFG_BASE | (offset & 0xfc)); 118 119 out_le32 ((volatile unsigned *)dev, value); 120 121 return 0; 122 } 123 124 void pci_init_board (void) 125 { 126 struct pci_controller *hose = (struct pci_controller *)&local_hose; 127 128 hose->first_busno = 0; 129 hose->last_busno = 0xff; 130 131 pci_set_region (hose->regions + 0, 132 CONFIG_SYS_PCI_MEMORY_BUS, 133 CONFIG_SYS_PCI_MEMORY_PHYS, 134 CONFIG_SYS_PCI_MEMORY_SIZE, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); 135 136 /* PCI memory space */ 137 pci_set_region (hose->regions + 1, 138 CONFIG_SYS_PCI_MEM_BUS, 139 CONFIG_SYS_PCI_MEM_PHYS, CONFIG_SYS_PCI_MEM_SIZE, PCI_REGION_MEM); 140 141 /* PCI I/O space */ 142 pci_set_region (hose->regions + 2, 143 CONFIG_SYS_PCI_IO_BUS, 144 CONFIG_SYS_PCI_IO_PHYS, CONFIG_SYS_PCI_IO_SIZE, PCI_REGION_IO); 145 146 hose->region_count = 3; 147 148 pci_set_ops (hose, 149 pci_hose_read_config_byte_via_dword, 150 pci_hose_read_config_word_via_dword, 151 tsi108_read_config_dword, 152 pci_hose_write_config_byte_via_dword, 153 pci_hose_write_config_word_via_dword, 154 tsi108_write_config_dword); 155 156 pci_register_hose (hose); 157 158 hose->last_busno = pci_hose_scan (hose); 159 160 debug ("Done PCI initialization\n"); 161 return; 162 } 163 164 #if defined(CONFIG_OF_LIBFDT) 165 void ft_pci_setup(void *blob, bd_t *bd) 166 { 167 int nodeoffset; 168 int tmp[2]; 169 const char *path; 170 171 nodeoffset = fdt_path_offset(blob, "/aliases"); 172 if (nodeoffset >= 0) { 173 path = fdt_getprop(blob, nodeoffset, "pci", NULL); 174 if (path) { 175 tmp[0] = cpu_to_be32(local_hose.first_busno); 176 tmp[1] = cpu_to_be32(local_hose.last_busno); 177 do_fixup_by_path(blob, path, "bus-range", 178 &tmp, sizeof(tmp), 1); 179 } 180 } 181 } 182 #endif /* CONFIG_OF_LIBFDT */ 183