tsi108_pci.c 4.5 KB
Newer Older
R
roy zang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
/*
 * (C) Copyright 2004 Tundra Semiconductor Corp.
 * Alex Bounine <alexandreb@tundra.com>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

/*
 * PCI initialisation for the Tsi108 EMU board.
 */

#include <config.h>

#ifdef CONFIG_TSI108_PCI

#include <common.h>
#include <pci.h>
#include <asm/io.h>
#include <tsi108.h>

struct pci_controller local_hose;

39
void tsi108_clear_pci_error (void)
R
roy zang 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
{
	u32 err_stat, err_addr, pci_stat;

	/*
	 * Quietly clear errors signalled as result of PCI/X configuration read
	 * requests.
	 */
	/* Read PB Error Log Registers */
	err_stat = *(volatile u32 *)(CFG_TSI108_CSR_BASE +
				     TSI108_PB_REG_OFFSET + PB_ERRCS);
	err_addr = *(volatile u32 *)(CFG_TSI108_CSR_BASE +
				     TSI108_PB_REG_OFFSET + PB_AERR);
	if (err_stat & PB_ERRCS_ES) {
		/* Clear PCI/X bus errors if applicable */
		if ((err_addr & 0xFF000000) == CFG_PCI_CFG_BASE) {
			/* Clear error flag */
			*(u32 *) (CFG_TSI108_CSR_BASE +
				  TSI108_PB_REG_OFFSET + PB_ERRCS) =
			    PB_ERRCS_ES;

			/* Clear read error reported in PB_ISR */
			*(u32 *) (CFG_TSI108_CSR_BASE +
				  TSI108_PB_REG_OFFSET + PB_ISR) =
			    PB_ISR_PBS_RD_ERR;

		/* Clear errors reported by PCI CSR (Normally Master Abort) */
			pci_stat = *(volatile u32 *)(CFG_TSI108_CSR_BASE +
						     TSI108_PCI_REG_OFFSET +
						     PCI_CSR);
			*(volatile u32 *)(CFG_TSI108_CSR_BASE +
					  TSI108_PCI_REG_OFFSET + PCI_CSR) =
			    pci_stat;

			*(volatile u32 *)(CFG_TSI108_CSR_BASE +
					  TSI108_PCI_REG_OFFSET +
					  PCI_IRP_STAT) = PCI_IRP_STAT_P_CSR;
		}
	}

	return;
}

82
unsigned int __get_pci_config_dword (u32 addr)
R
roy zang 已提交
83 84 85
{
	unsigned int retval;

86
	__asm__ __volatile__ ("       lwbrx %0,0,%1\n"
R
roy zang 已提交
87 88 89 90 91 92 93 94 95 96 97 98 99
			     "1:     eieio\n"
			     "2:\n"
			     ".section .fixup,\"ax\"\n"
			     "3:     li %0,-1\n"
			     "       b 2b\n"
			     ".section __ex_table,\"a\"\n"
			     "       .align 2\n"
			     "       .long 1b,3b\n"
			     ".text":"=r"(retval):"r"(addr));

	return (retval);
}

100
static int tsi108_read_config_dword (struct pci_controller *hose,
R
roy zang 已提交
101 102 103 104 105 106
				    pci_dev_t dev, int offset, u32 * value)
{
	dev &= (CFG_PCI_CFG_SIZE - 1);
	dev |= (CFG_PCI_CFG_BASE | (offset & 0xfc));
	*value = __get_pci_config_dword(dev);
	if (0xFFFFFFFF == *value)
107
		tsi108_clear_pci_error ();
R
roy zang 已提交
108 109 110
	return 0;
}

111
static int tsi108_write_config_dword (struct pci_controller *hose,
R
roy zang 已提交
112 113 114 115 116
				     pci_dev_t dev, int offset, u32 value)
{
	dev &= (CFG_PCI_CFG_SIZE - 1);
	dev |= (CFG_PCI_CFG_BASE | (offset & 0xfc));

117
	out_le32 ((volatile unsigned *)dev, value);
R
roy zang 已提交
118 119 120 121

	return 0;
}

122
void pci_init_board (void)
R
roy zang 已提交
123 124 125 126 127 128
{
	struct pci_controller *hose = (struct pci_controller *)&local_hose;

	hose->first_busno = 0;
	hose->last_busno = 0xff;

129
	pci_set_region (hose->regions + 0,
R
roy zang 已提交
130 131 132 133 134
		       CFG_PCI_MEMORY_BUS,
		       CFG_PCI_MEMORY_PHYS,
		       CFG_PCI_MEMORY_SIZE, PCI_REGION_MEM | PCI_REGION_MEMORY);

	/* PCI memory space */
135
	pci_set_region (hose->regions + 1,
R
roy zang 已提交
136 137 138 139
		       CFG_PCI_MEM_BUS,
		       CFG_PCI_MEM_PHYS, CFG_PCI_MEM_SIZE, PCI_REGION_MEM);

	/* PCI I/O space */
140
	pci_set_region (hose->regions + 2,
R
roy zang 已提交
141 142 143 144 145
		       CFG_PCI_IO_BUS,
		       CFG_PCI_IO_PHYS, CFG_PCI_IO_SIZE, PCI_REGION_IO);

	hose->region_count = 3;

146
	pci_set_ops (hose,
R
roy zang 已提交
147 148 149 150 151 152 153
		    pci_hose_read_config_byte_via_dword,
		    pci_hose_read_config_word_via_dword,
		    tsi108_read_config_dword,
		    pci_hose_write_config_byte_via_dword,
		    pci_hose_write_config_word_via_dword,
		    tsi108_write_config_dword);

154
	pci_register_hose (hose);
R
roy zang 已提交
155

156
	hose->last_busno = pci_hose_scan (hose);
R
roy zang 已提交
157

158
	debug ("Done PCI initialization\n");
R
roy zang 已提交
159 160 161 162 163
	return;
}

#ifdef CONFIG_OF_FLAT_TREE
void
164
ft_pci_setup (void *blob, bd_t *bd)
R
roy zang 已提交
165 166 167 168
{
	u32 *p;
	int len;

169
	p = (u32 *)ft_get_prop (blob, "/" OF_TSI "/pci@1000/bus-range", &len);
R
roy zang 已提交
170 171 172 173 174 175 176 177 178
	if (p != NULL) {
		p[0] = local_hose.first_busno;
		p[1] = local_hose.last_busno;
	}

}
#endif

#endif	/* CONFIG_TSI108_PCI */