diff options
author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2007-07-02 09:43:06 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-07-10 12:33:04 -0400 |
commit | 2db30150fe4fe309c57087c661209c9ea0b5c21b (patch) | |
tree | 7f327ade219e352f3819ab3cd8d53690b75a79d6 /arch/mips/pci/ops-tx4938.c | |
parent | bd43da8ff130caf31fff0482a75660507a26b641 (diff) |
[MIPS] rbtx4938: Fix secondary PCIC and glue internal NICs
* Fix pci ops for secondary PCIC
* Do not reserve 1MB for PCI MEM region (leave PCIBIOS_MIN_MEM zero)
* Use platform_device to provide ethernet addresses for internal NICs.
(background: TX49XX SoCs include PCI NIC (TC35815 compatible)
connected via its internal PCI bus, but the NIC's PROM interface is
not connected to SEEPROM. So we must provide its ethernet address
by another way.)
* Check return value of early_read_config_word()
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/pci/ops-tx4938.c')
-rw-r--r-- | arch/mips/pci/ops-tx4938.c | 80 |
1 files changed, 48 insertions, 32 deletions
diff --git a/arch/mips/pci/ops-tx4938.c b/arch/mips/pci/ops-tx4938.c index 445007084515..a450c4062031 100644 --- a/arch/mips/pci/ops-tx4938.c +++ b/arch/mips/pci/ops-tx4938.c | |||
@@ -46,50 +46,63 @@ struct resource tx4938_pcic1_pci_mem_resource = { | |||
46 | .flags = IORESOURCE_MEM | 46 | .flags = IORESOURCE_MEM |
47 | }; | 47 | }; |
48 | 48 | ||
49 | static int mkaddr(int bus, int dev_fn, int where, int *flagsp) | 49 | static int mkaddr(int bus, int dev_fn, int where, |
50 | struct tx4938_pcic_reg *pcicptr) | ||
50 | { | 51 | { |
51 | if (bus > 0) { | 52 | if (bus > 0) { |
52 | /* Type 1 configuration */ | 53 | /* Type 1 configuration */ |
53 | tx4938_pcicptr->g2pcfgadrs = ((bus & 0xff) << 0x10) | | 54 | pcicptr->g2pcfgadrs = ((bus & 0xff) << 0x10) | |
54 | ((dev_fn & 0xff) << 0x08) | (where & 0xfc) | 1; | 55 | ((dev_fn & 0xff) << 0x08) | (where & 0xfc) | 1; |
55 | } else { | 56 | } else { |
56 | if (dev_fn >= PCI_DEVFN(TX4938_PCIC_MAX_DEVNU, 0)) | 57 | if (dev_fn >= PCI_DEVFN(TX4938_PCIC_MAX_DEVNU, 0)) |
57 | return -1; | 58 | return -1; |
58 | 59 | ||
59 | /* Type 0 configuration */ | 60 | /* Type 0 configuration */ |
60 | tx4938_pcicptr->g2pcfgadrs = ((bus & 0xff) << 0x10) | | 61 | pcicptr->g2pcfgadrs = ((bus & 0xff) << 0x10) | |
61 | ((dev_fn & 0xff) << 0x08) | (where & 0xfc); | 62 | ((dev_fn & 0xff) << 0x08) | (where & 0xfc); |
62 | } | 63 | } |
63 | /* clear M_ABORT and Disable M_ABORT Int. */ | 64 | /* clear M_ABORT and Disable M_ABORT Int. */ |
64 | tx4938_pcicptr->pcistatus = | 65 | pcicptr->pcistatus = |
65 | (tx4938_pcicptr->pcistatus & 0x0000ffff) | | 66 | (pcicptr->pcistatus & 0x0000ffff) | |
66 | (PCI_STATUS_REC_MASTER_ABORT << 16); | 67 | (PCI_STATUS_REC_MASTER_ABORT << 16); |
67 | tx4938_pcicptr->pcimask &= ~PCI_STATUS_REC_MASTER_ABORT; | 68 | pcicptr->pcimask &= ~PCI_STATUS_REC_MASTER_ABORT; |
68 | 69 | ||
69 | return 0; | 70 | return 0; |
70 | } | 71 | } |
71 | 72 | ||
72 | static int check_abort(int flags) | 73 | static int check_abort(struct tx4938_pcic_reg *pcicptr) |
73 | { | 74 | { |
74 | int code = PCIBIOS_SUCCESSFUL; | 75 | int code = PCIBIOS_SUCCESSFUL; |
75 | /* wait write cycle completion before checking error status */ | 76 | /* wait write cycle completion before checking error status */ |
76 | while (tx4938_pcicptr->pcicstatus & TX4938_PCIC_PCICSTATUS_IWB) | 77 | while (pcicptr->pcicstatus & TX4938_PCIC_PCICSTATUS_IWB) |
77 | ; | 78 | ; |
78 | if (tx4938_pcicptr->pcistatus & (PCI_STATUS_REC_MASTER_ABORT << 16)) { | 79 | if (pcicptr->pcistatus & (PCI_STATUS_REC_MASTER_ABORT << 16)) { |
79 | tx4938_pcicptr->pcistatus = | 80 | pcicptr->pcistatus = |
80 | (tx4938_pcicptr-> | 81 | (pcicptr-> |
81 | pcistatus & 0x0000ffff) | (PCI_STATUS_REC_MASTER_ABORT | 82 | pcistatus & 0x0000ffff) | (PCI_STATUS_REC_MASTER_ABORT |
82 | << 16); | 83 | << 16); |
83 | tx4938_pcicptr->pcimask |= PCI_STATUS_REC_MASTER_ABORT; | 84 | pcicptr->pcimask |= PCI_STATUS_REC_MASTER_ABORT; |
84 | code = PCIBIOS_DEVICE_NOT_FOUND; | 85 | code = PCIBIOS_DEVICE_NOT_FOUND; |
85 | } | 86 | } |
86 | return code; | 87 | return code; |
87 | } | 88 | } |
88 | 89 | ||
90 | extern struct pci_controller tx4938_pci_controller[]; | ||
91 | extern struct tx4938_pcic_reg *get_tx4938_pcicptr(int ch); | ||
92 | |||
93 | static struct tx4938_pcic_reg *pci_bus_to_pcicptr(struct pci_bus *bus) | ||
94 | { | ||
95 | struct pci_controller *channel = bus->sysdata; | ||
96 | return get_tx4938_pcicptr(channel - &tx4938_pci_controller[0]); | ||
97 | } | ||
98 | |||
89 | static int tx4938_pcibios_read_config(struct pci_bus *bus, unsigned int devfn, | 99 | static int tx4938_pcibios_read_config(struct pci_bus *bus, unsigned int devfn, |
90 | int where, int size, u32 * val) | 100 | int where, int size, u32 * val) |
91 | { | 101 | { |
92 | int flags, retval, dev, busno, func; | 102 | int retval, dev, busno, func; |
103 | struct tx4938_pcic_reg *pcicptr = pci_bus_to_pcicptr(bus); | ||
104 | void __iomem *cfgdata = | ||
105 | (void __iomem *)(unsigned long)&pcicptr->g2pcfgdata; | ||
93 | 106 | ||
94 | dev = PCI_SLOT(devfn); | 107 | dev = PCI_SLOT(devfn); |
95 | func = PCI_FUNC(devfn); | 108 | func = PCI_FUNC(devfn); |
@@ -101,32 +114,32 @@ static int tx4938_pcibios_read_config(struct pci_bus *bus, unsigned int devfn, | |||
101 | busno = 0; | 114 | busno = 0; |
102 | } | 115 | } |
103 | 116 | ||
104 | if (mkaddr(busno, devfn, where, &flags)) | 117 | if (mkaddr(busno, devfn, where, pcicptr)) |
105 | return -1; | 118 | return -1; |
106 | 119 | ||
107 | switch (size) { | 120 | switch (size) { |
108 | case 1: | 121 | case 1: |
109 | *val = *(volatile u8 *) ((unsigned long) & tx4938_pcicptr->g2pcfgdata | | ||
110 | #ifdef __BIG_ENDIAN | 122 | #ifdef __BIG_ENDIAN |
111 | ((where & 3) ^ 3)); | 123 | cfgdata += (where & 3) ^ 3; |
112 | #else | 124 | #else |
113 | (where & 3)); | 125 | cfgdata += where & 3; |
114 | #endif | 126 | #endif |
127 | *val = __raw_readb(cfgdata); | ||
115 | break; | 128 | break; |
116 | case 2: | 129 | case 2: |
117 | *val = *(volatile u16 *) ((unsigned long) & tx4938_pcicptr->g2pcfgdata | | ||
118 | #ifdef __BIG_ENDIAN | 130 | #ifdef __BIG_ENDIAN |
119 | ((where & 3) ^ 2)); | 131 | cfgdata += (where & 2) ^ 2; |
120 | #else | 132 | #else |
121 | (where & 3)); | 133 | cfgdata += where & 2; |
122 | #endif | 134 | #endif |
135 | *val = __raw_readw(cfgdata); | ||
123 | break; | 136 | break; |
124 | case 4: | 137 | case 4: |
125 | *val = tx4938_pcicptr->g2pcfgdata; | 138 | *val = __raw_readl(cfgdata); |
126 | break; | 139 | break; |
127 | } | 140 | } |
128 | 141 | ||
129 | retval = check_abort(flags); | 142 | retval = check_abort(pcicptr); |
130 | if (retval == PCIBIOS_DEVICE_NOT_FOUND) | 143 | if (retval == PCIBIOS_DEVICE_NOT_FOUND) |
131 | *val = 0xffffffff; | 144 | *val = 0xffffffff; |
132 | 145 | ||
@@ -136,7 +149,10 @@ static int tx4938_pcibios_read_config(struct pci_bus *bus, unsigned int devfn, | |||
136 | static int tx4938_pcibios_write_config(struct pci_bus *bus, unsigned int devfn, int where, | 149 | static int tx4938_pcibios_write_config(struct pci_bus *bus, unsigned int devfn, int where, |
137 | int size, u32 val) | 150 | int size, u32 val) |
138 | { | 151 | { |
139 | int flags, dev, busno, func; | 152 | int dev, busno, func; |
153 | struct tx4938_pcic_reg *pcicptr = pci_bus_to_pcicptr(bus); | ||
154 | void __iomem *cfgdata = | ||
155 | (void __iomem *)(unsigned long)&pcicptr->g2pcfgdata; | ||
140 | 156 | ||
141 | busno = bus->number; | 157 | busno = bus->number; |
142 | dev = PCI_SLOT(devfn); | 158 | dev = PCI_SLOT(devfn); |
@@ -149,32 +165,32 @@ static int tx4938_pcibios_write_config(struct pci_bus *bus, unsigned int devfn, | |||
149 | busno = 0; | 165 | busno = 0; |
150 | } | 166 | } |
151 | 167 | ||
152 | if (mkaddr(busno, devfn, where, &flags)) | 168 | if (mkaddr(busno, devfn, where, pcicptr)) |
153 | return -1; | 169 | return -1; |
154 | 170 | ||
155 | switch (size) { | 171 | switch (size) { |
156 | case 1: | 172 | case 1: |
157 | *(volatile u8 *) ((unsigned long) & tx4938_pcicptr->g2pcfgdata | | ||
158 | #ifdef __BIG_ENDIAN | 173 | #ifdef __BIG_ENDIAN |
159 | ((where & 3) ^ 3)) = val; | 174 | cfgdata += (where & 3) ^ 3; |
160 | #else | 175 | #else |
161 | (where & 3)) = val; | 176 | cfgdata += where & 3; |
162 | #endif | 177 | #endif |
178 | __raw_writeb(val, cfgdata); | ||
163 | break; | 179 | break; |
164 | case 2: | 180 | case 2: |
165 | *(volatile u16 *) ((unsigned long) & tx4938_pcicptr->g2pcfgdata | | ||
166 | #ifdef __BIG_ENDIAN | 181 | #ifdef __BIG_ENDIAN |
167 | ((where & 0x3) ^ 0x2)) = val; | 182 | cfgdata += (where & 2) ^ 2; |
168 | #else | 183 | #else |
169 | (where & 3)) = val; | 184 | cfgdata += where & 2; |
170 | #endif | 185 | #endif |
186 | __raw_writew(val, cfgdata); | ||
171 | break; | 187 | break; |
172 | case 4: | 188 | case 4: |
173 | tx4938_pcicptr->g2pcfgdata = val; | 189 | __raw_writel(val, cfgdata); |
174 | break; | 190 | break; |
175 | } | 191 | } |
176 | 192 | ||
177 | return check_abort(flags); | 193 | return check_abort(pcicptr); |
178 | } | 194 | } |
179 | 195 | ||
180 | struct pci_ops tx4938_pci_ops = { | 196 | struct pci_ops tx4938_pci_ops = { |