pci_indirect.c 4.6 KB
Newer Older
W
wdenk 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * Support for indirect PCI bridges.
 *
 * Copyright (C) 1998 Gabriel Paubert.
 *
 * 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.
 */

#include <common.h>

M
Michael Schwingen 已提交
14
#if !defined(__I386__)
W
wdenk 已提交
15 16 17 18 19 20 21 22

#include <asm/processor.h>
#include <asm/io.h>
#include <pci.h>

#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
#define cfg_write(val, addr, type, op)	op((type *)(addr), (val))

W
wdenk 已提交
23
#if defined(CONFIG_MPC8260)
W
wdenk 已提交
24 25
#define INDIRECT_PCI_OP(rw, size, type, op, mask)			 \
static int								 \
W
Wolfgang Denk 已提交
26
indirect_##rw##_config_##size(struct pci_controller *hose,		 \
W
wdenk 已提交
27 28
			      pci_dev_t dev, int offset, type val)	 \
{									 \
29 30 31 32
	u32 b, d,f;							 \
	b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev);		 \
	b = b - hose->first_busno;					 \
	dev = PCI_BDF(b, d, f);						 \
W
Wolfgang Denk 已提交
33
	out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000);	 \
34
	sync();								 \
W
wdenk 已提交
35
	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);	 \
W
Wolfgang Denk 已提交
36
	return 0;							 \
W
wdenk 已提交
37
}
38
#elif defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
W
wdenk 已提交
39 40 41 42 43
#define INDIRECT_PCI_OP(rw, size, type, op, mask)                        \
static int                                                               \
indirect_##rw##_config_##size(struct pci_controller *hose,               \
			      pci_dev_t dev, int offset, type val)       \
{                                                                        \
44 45 46 47
	u32 b, d,f;							 \
	b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev);		 \
	b = b - hose->first_busno;					 \
	dev = PCI_BDF(b, d, f);						 \
48
	*(hose->cfg_addr) = dev | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000; \
W
wdenk 已提交
49 50 51 52
	sync();                                                          \
	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);       \
	return 0;                                                        \
}
53 54
#elif defined(CONFIG_440GX)  || defined(CONFIG_440GP) || defined(CONFIG_440SP) || \
      defined(CONFIG_440SPE) || defined(CONFIG_460EX) || defined(CONFIG_460GT)
W
wdenk 已提交
55 56
#define INDIRECT_PCI_OP(rw, size, type, op, mask)			 \
static int								 \
W
Wolfgang Denk 已提交
57
indirect_##rw##_config_##size(struct pci_controller *hose,		 \
W
wdenk 已提交
58 59
			      pci_dev_t dev, int offset, type val)	 \
{									 \
60 61 62 63
	u32 b, d,f;							 \
	b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev);		 \
	b = b - hose->first_busno;					 \
	dev = PCI_BDF(b, d, f);						 \
W
wdenk 已提交
64 65 66 67 68
	if (PCI_BUS(dev) > 0)                                            \
		out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000001); \
	else                                                             \
		out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);	 \
W
Wolfgang Denk 已提交
69
	return 0;							 \
W
wdenk 已提交
70
}
71 72 73
#else
#define INDIRECT_PCI_OP(rw, size, type, op, mask)			 \
static int								 \
W
Wolfgang Denk 已提交
74
indirect_##rw##_config_##size(struct pci_controller *hose,		 \
75 76
			      pci_dev_t dev, int offset, type val)	 \
{									 \
77 78 79 80
	u32 b, d,f;							 \
	b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev);		 \
	b = b - hose->first_busno;					 \
	dev = PCI_BDF(b, d, f);						 \
W
Wolfgang Denk 已提交
81
	out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000);	 \
82
	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);	 \
W
Wolfgang Denk 已提交
83
	return 0;							 \
84 85
}
#endif
W
wdenk 已提交
86 87 88

#define INDIRECT_PCI_OP_ERRATA6(rw, size, type, op, mask)		 \
static int								 \
W
Wolfgang Denk 已提交
89
indirect_##rw##_config_##size(struct pci_controller *hose,		 \
W
wdenk 已提交
90 91 92 93
			      pci_dev_t dev, int offset, type val)	 \
{									 \
	unsigned int msr = mfmsr();					 \
	mtmsr(msr & ~(MSR_EE | MSR_CE));				 \
W
Wolfgang Denk 已提交
94
	out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000);	 \
W
wdenk 已提交
95
	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);	 \
W
Wolfgang Denk 已提交
96
	out_le32(hose->cfg_addr, 0x00000000);				 \
W
wdenk 已提交
97
	mtmsr(msr);							 \
W
Wolfgang Denk 已提交
98
	return 0;							 \
W
wdenk 已提交
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
}

INDIRECT_PCI_OP(read, byte, u8 *, in_8, 3)
INDIRECT_PCI_OP(read, word, u16 *, in_le16, 2)
INDIRECT_PCI_OP(read, dword, u32 *, in_le32, 0)
#ifdef CONFIG_405GP
INDIRECT_PCI_OP_ERRATA6(write, byte, u8, out_8, 3)
INDIRECT_PCI_OP_ERRATA6(write, word, u16, out_le16, 2)
INDIRECT_PCI_OP_ERRATA6(write, dword, u32, out_le32, 0)
#else
INDIRECT_PCI_OP(write, byte, u8, out_8, 3)
INDIRECT_PCI_OP(write, word, u16, out_le16, 2)
INDIRECT_PCI_OP(write, dword, u32, out_le32, 0)
#endif

void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
{
	pci_set_ops(hose,
		    indirect_read_config_byte,
		    indirect_read_config_word,
		    indirect_read_config_dword,
		    indirect_write_config_byte,
		    indirect_write_config_word,
		    indirect_write_config_dword);

	hose->cfg_addr = (unsigned int *) cfg_addr;
	hose->cfg_data = (unsigned char *) cfg_data;
}

M
Michael Schwingen 已提交
128
#endif	/* !__I386__ */