]>
Commit | Line | Data |
---|---|---|
c609719b WD |
1 | /* PCI.c - PCI functions */ |
2 | ||
3 | /* Copyright - Galileo technology. */ | |
4 | ||
5 | #include <common.h> | |
6 | #include <pci.h> | |
7 | ||
8 | #include <galileo/pci.h> | |
9 | ||
10 | static const unsigned char pci_irq_swizzle[2][PCI_MAX_DEVICES] = { | |
11 | #ifdef CONFIG_ZUMA_V2 | |
12 | {0,0,0,0,0,0,0,29, [8 ... PCI_MAX_DEVICES-1]=0}, | |
13 | {0,0,0,0,0,0,0,28, [8 ... PCI_MAX_DEVICES-1]=0} | |
14 | #else /* EVB??? This is a guess */ | |
15 | {0,0,0,0,0,0,0,27,27, [9 ... PCI_MAX_DEVICES-1]=0}, | |
16 | {0,0,0,0,0,0,0,29,29, [9 ... PCI_MAX_DEVICES-1]=0} | |
17 | #endif | |
18 | }; | |
19 | ||
20 | static const unsigned int pci_p2p_configuration_reg[]={ | |
21 | PCI_0P2P_CONFIGURATION, PCI_1P2P_CONFIGURATION}; | |
22 | ||
23 | static const unsigned int pci_configuration_address[]={ | |
24 | PCI_0CONFIGURATION_ADDRESS, PCI_1CONFIGURATION_ADDRESS}; | |
25 | ||
26 | static const unsigned int pci_configuration_data[]={ | |
27 | PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER, | |
28 | PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER}; | |
29 | ||
30 | static const unsigned int pci_error_cause_reg[]={ | |
31 | PCI_0ERROR_CAUSE, PCI_1ERROR_CAUSE}; | |
32 | ||
33 | static const unsigned int pci_arbiter_control[]={ | |
34 | PCI_0ARBITER_CONTROL, PCI_1ARBITER_CONTROL}; | |
35 | ||
36 | static const unsigned int pci_snoop_control_base_0_low[]={ | |
37 | PCI_0SNOOP_CONTROL_BASE_0_LOW, PCI_1SNOOP_CONTROL_BASE_0_LOW}; | |
38 | static const unsigned int pci_snoop_control_top_0[]={ | |
39 | PCI_0SNOOP_CONTROL_TOP_0, PCI_1SNOOP_CONTROL_TOP_0}; | |
40 | ||
41 | static const unsigned int pci_access_control_base_0_low[]={ | |
42 | PCI_0ACCESS_CONTROL_BASE_0_LOW, PCI_1ACCESS_CONTROL_BASE_0_LOW}; | |
43 | static const unsigned int pci_access_control_top_0[]={ | |
44 | PCI_0ACCESS_CONTROL_TOP_0, PCI_1ACCESS_CONTROL_TOP_0}; | |
45 | ||
46 | static const unsigned int pci_scs_bank_size[2][4] = { | |
47 | {PCI_0SCS_0_BANK_SIZE, PCI_0SCS_1_BANK_SIZE, | |
48 | PCI_0SCS_2_BANK_SIZE, PCI_0SCS_3_BANK_SIZE}, | |
49 | {PCI_1SCS_0_BANK_SIZE, PCI_1SCS_1_BANK_SIZE, | |
50 | PCI_1SCS_2_BANK_SIZE, PCI_1SCS_3_BANK_SIZE}}; | |
51 | ||
52 | static const unsigned int pci_p2p_configuration[] = { | |
53 | PCI_0P2P_CONFIGURATION, PCI_1P2P_CONFIGURATION}; | |
54 | ||
db2f721f | 55 | static unsigned int local_buses[] = { 0, 0}; |
c609719b WD |
56 | /******************************************************************** |
57 | * pciWriteConfigReg - Write to a PCI configuration register | |
58 | * - Make sure the GT is configured as a master before writing | |
59 | * to another device on the PCI. | |
60 | * - The function takes care of Big/Little endian conversion. | |
61 | * | |
62 | * | |
63 | * Inputs: unsigned int regOffset: The register offset as it apears in the GT spec | |
64 | * (or any other PCI device spec) | |
65 | * pciDevNum: The device number needs to be addressed. | |
66 | * | |
67 | * Configuration Address 0xCF8: | |
68 | * | |
69 | * 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number | |
70 | * |congif|Reserved| Bus |Device|Function|Register|00| | |
71 | * |Enable| |Number|Number| Number | Number | | <=field Name | |
72 | * | |
73 | *********************************************************************/ | |
74 | void pciWriteConfigReg(PCI_HOST host, unsigned int regOffset,unsigned int pciDevNum,unsigned int data) | |
75 | { | |
76 | volatile unsigned int DataForAddrReg; | |
77 | unsigned int functionNum; | |
db2f721f | 78 | unsigned int busNum = PCI_BUS(pciDevNum); |
c609719b WD |
79 | unsigned int addr; |
80 | ||
81 | if(pciDevNum > 32) /* illegal device Number */ | |
8bde7f77 | 82 | return; |
c609719b WD |
83 | if(pciDevNum == SELF) /* configure our configuration space. */ |
84 | { | |
8bde7f77 WD |
85 | pciDevNum = (GTREGREAD(pci_p2p_configuration_reg[host]) >> 24) & 0x1f; |
86 | busNum = GTREGREAD(pci_p2p_configuration_reg[host]) & 0xff0000; | |
c609719b WD |
87 | } |
88 | functionNum = regOffset & 0x00000700; | |
89 | pciDevNum = pciDevNum << 11; | |
90 | regOffset = regOffset & 0xfc; | |
91 | DataForAddrReg = ( regOffset | pciDevNum | functionNum | busNum) | BIT31; | |
92 | GT_REG_WRITE(pci_configuration_address[host],DataForAddrReg); | |
93 | GT_REG_READ(pci_configuration_address[host], &addr); | |
94 | if (addr != DataForAddrReg) return; | |
95 | GT_REG_WRITE(pci_configuration_data[host],data); | |
96 | } | |
97 | ||
98 | /******************************************************************** | |
99 | * pciReadConfigReg - Read from a PCI0 configuration register | |
100 | * - Make sure the GT is configured as a master before reading | |
101 | * from another device on the PCI. | |
102 | * - The function takes care of Big/Little endian conversion. | |
103 | * INPUTS: regOffset: The register offset as it apears in the GT spec (or PCI | |
104 | * spec) | |
105 | * pciDevNum: The device number needs to be addressed. | |
106 | * RETURNS: data , if the data == 0xffffffff check the master abort bit in the | |
107 | * cause register to make sure the data is valid | |
108 | * | |
109 | * Configuration Address 0xCF8: | |
110 | * | |
111 | * 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number | |
112 | * |congif|Reserved| Bus |Device|Function|Register|00| | |
113 | * |Enable| |Number|Number| Number | Number | | <=field Name | |
114 | * | |
115 | *********************************************************************/ | |
116 | unsigned int pciReadConfigReg (PCI_HOST host, unsigned int regOffset,unsigned int pciDevNum) | |
117 | { | |
118 | volatile unsigned int DataForAddrReg; | |
8bde7f77 | 119 | unsigned int data; |
c609719b | 120 | unsigned int functionNum; |
db2f721f | 121 | unsigned int busNum = PCI_BUS(pciDevNum); |
c609719b WD |
122 | |
123 | if(pciDevNum > 32) /* illegal device Number */ | |
8bde7f77 | 124 | return 0xffffffff; |
c609719b WD |
125 | if(pciDevNum == SELF) /* configure our configuration space. */ |
126 | { | |
8bde7f77 WD |
127 | pciDevNum = (GTREGREAD(pci_p2p_configuration_reg[host]) >> 24) & 0x1f; |
128 | busNum = GTREGREAD(pci_p2p_configuration_reg[host]) & 0xff0000; | |
c609719b WD |
129 | } |
130 | functionNum = regOffset & 0x00000700; | |
131 | pciDevNum = pciDevNum << 11; | |
132 | regOffset = regOffset & 0xfc; | |
133 | DataForAddrReg = (regOffset | pciDevNum | functionNum | busNum) | BIT31 ; | |
134 | GT_REG_WRITE(pci_configuration_address[host],DataForAddrReg); | |
135 | GT_REG_READ(pci_configuration_address[host], &data); | |
136 | if (data != DataForAddrReg) | |
8bde7f77 | 137 | return 0xffffffff; |
c609719b WD |
138 | GT_REG_READ(pci_configuration_data[host], &data); |
139 | return data; | |
140 | } | |
141 | ||
142 | /******************************************************************** | |
143 | * pciOverBridgeWriteConfigReg - Write to a PCI configuration register where | |
144 | * the agent is placed on another Bus. For more | |
145 | * information read P2P in the PCI spec. | |
146 | * | |
147 | * Inputs: unsigned int regOffset - The register offset as it apears in the | |
148 | * GT spec (or any other PCI device spec). | |
149 | * unsigned int pciDevNum - The device number needs to be addressed. | |
150 | * unsigned int busNum - On which bus does the Target agent connect | |
151 | * to. | |
152 | * unsigned int data - data to be written. | |
153 | * | |
154 | * Configuration Address 0xCF8: | |
155 | * | |
156 | * 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number | |
157 | * |congif|Reserved| Bus |Device|Function|Register|01| | |
158 | * |Enable| |Number|Number| Number | Number | | <=field Name | |
159 | * | |
160 | * The configuration Address is configure as type-I (bits[1:0] = '01') due to | |
161 | * PCI spec referring to P2P. | |
162 | * | |
163 | *********************************************************************/ | |
164 | void pciOverBridgeWriteConfigReg(PCI_HOST host, | |
165 | unsigned int regOffset, | |
8bde7f77 WD |
166 | unsigned int pciDevNum, |
167 | unsigned int busNum,unsigned int data) | |
c609719b | 168 | { |
8bde7f77 | 169 | unsigned int DataForReg; |
c609719b WD |
170 | unsigned int functionNum; |
171 | ||
8bde7f77 | 172 | functionNum = regOffset & 0x00000700; |
c609719b WD |
173 | pciDevNum = pciDevNum << 11; |
174 | regOffset = regOffset & 0xff; | |
175 | busNum = busNum << 16; | |
176 | if(pciDevNum == SELF) /* This board */ | |
177 | { | |
8bde7f77 | 178 | DataForReg = ( regOffset | pciDevNum | functionNum) | BIT0; |
c609719b WD |
179 | } |
180 | else | |
181 | { | |
8bde7f77 WD |
182 | DataForReg = ( regOffset | pciDevNum | functionNum | busNum) | |
183 | BIT31 | BIT0; | |
c609719b WD |
184 | } |
185 | GT_REG_WRITE(pci_configuration_address[host],DataForReg); | |
186 | if(pciDevNum == SELF) /* This board */ | |
187 | { | |
8bde7f77 | 188 | GT_REG_WRITE(pci_configuration_data[host],data); |
c609719b WD |
189 | } |
190 | else /* configuration Transaction over the pci. */ | |
191 | { | |
8bde7f77 WD |
192 | /* The PCI is working in LE Mode So it swap the Data. */ |
193 | GT_REG_WRITE(pci_configuration_data[host],WORD_SWAP(data)); | |
c609719b WD |
194 | } |
195 | } | |
196 | ||
197 | ||
198 | /******************************************************************** | |
199 | * pciOverBridgeReadConfigReg - Read from a PCIn configuration register where | |
200 | * the agent target locate on another PCI bus. | |
201 | * - Make sure the GT is configured as a master | |
202 | * before reading from another device on the PCI. | |
203 | * - The function takes care of Big/Little endian | |
204 | * conversion. | |
205 | * INPUTS: regOffset: The register offset as it apears in the GT spec (or PCI | |
206 | * spec). (configuration register offset.) | |
207 | * pciDevNum: The device number needs to be addressed. | |
208 | * busNum: the Bus number where the agent is place. | |
209 | * RETURNS: data , if the data == 0xffffffff check the master abort bit in the | |
210 | * cause register to make sure the data is valid | |
211 | * | |
212 | * Configuration Address 0xCF8: | |
213 | * | |
214 | * 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number | |
215 | * |congif|Reserved| Bus |Device|Function|Register|01| | |
216 | * |Enable| |Number|Number| Number | Number | | <=field Name | |
217 | * | |
218 | *********************************************************************/ | |
219 | unsigned int pciOverBridgeReadConfigReg(PCI_HOST host, | |
220 | unsigned int regOffset, | |
8bde7f77 WD |
221 | unsigned int pciDevNum, |
222 | unsigned int busNum) | |
c609719b WD |
223 | { |
224 | unsigned int DataForReg; | |
225 | unsigned int data; | |
226 | unsigned int functionNum; | |
227 | ||
228 | functionNum = regOffset & 0x00000700; | |
229 | pciDevNum = pciDevNum << 11; | |
230 | regOffset = regOffset & 0xff; | |
231 | busNum = busNum << 16; | |
232 | if (pciDevNum == SELF) /* This board */ | |
233 | { | |
8bde7f77 | 234 | DataForReg = (regOffset | pciDevNum | functionNum) | BIT31 ; |
c609719b WD |
235 | } |
236 | else /* agent on another bus */ | |
237 | { | |
8bde7f77 WD |
238 | DataForReg = (regOffset | pciDevNum | functionNum | busNum) | |
239 | BIT0 | BIT31 ; | |
c609719b WD |
240 | } |
241 | GT_REG_WRITE(pci_configuration_address[host],DataForReg); | |
242 | if (pciDevNum == SELF) /* This board */ | |
8bde7f77 WD |
243 | { |
244 | GT_REG_READ(pci_configuration_data[host], &data); | |
245 | return data; | |
c609719b WD |
246 | } |
247 | else /* The PCI is working in LE Mode So it swap the Data. */ | |
248 | { | |
8bde7f77 WD |
249 | GT_REG_READ(pci_configuration_data[host], &data); |
250 | return WORD_SWAP(data); | |
c609719b WD |
251 | } |
252 | } | |
253 | ||
254 | /******************************************************************** | |
255 | * pciGetRegOffset - Gets the register offset for this region config. | |
256 | * | |
257 | * INPUT: Bus, Region - The bus and region we ask for its base address. | |
258 | * OUTPUT: N/A | |
259 | * RETURNS: PCI register base address | |
260 | *********************************************************************/ | |
261 | static unsigned int pciGetRegOffset(PCI_HOST host, PCI_REGION region) | |
262 | { | |
263 | switch (host) | |
264 | { | |
265 | case PCI_HOST0: | |
266 | switch(region) { | |
267 | case PCI_IO: return PCI_0I_O_LOW_DECODE_ADDRESS; | |
268 | case PCI_REGION0: return PCI_0MEMORY0_LOW_DECODE_ADDRESS; | |
269 | case PCI_REGION1: return PCI_0MEMORY1_LOW_DECODE_ADDRESS; | |
270 | case PCI_REGION2: return PCI_0MEMORY2_LOW_DECODE_ADDRESS; | |
271 | case PCI_REGION3: return PCI_0MEMORY3_LOW_DECODE_ADDRESS; | |
272 | } | |
273 | case PCI_HOST1: | |
274 | switch(region) { | |
275 | case PCI_IO: return PCI_1I_O_LOW_DECODE_ADDRESS; | |
276 | case PCI_REGION0: return PCI_1MEMORY0_LOW_DECODE_ADDRESS; | |
277 | case PCI_REGION1: return PCI_1MEMORY1_LOW_DECODE_ADDRESS; | |
278 | case PCI_REGION2: return PCI_1MEMORY2_LOW_DECODE_ADDRESS; | |
279 | case PCI_REGION3: return PCI_1MEMORY3_LOW_DECODE_ADDRESS; | |
280 | } | |
281 | } | |
282 | return PCI_0MEMORY0_LOW_DECODE_ADDRESS; | |
283 | } | |
284 | ||
285 | static unsigned int pciGetRemapOffset(PCI_HOST host, PCI_REGION region) | |
286 | { | |
287 | switch (host) | |
288 | { | |
289 | case PCI_HOST0: | |
290 | switch(region) { | |
291 | case PCI_IO: return PCI_0I_O_ADDRESS_REMAP; | |
292 | case PCI_REGION0: return PCI_0MEMORY0_ADDRESS_REMAP; | |
293 | case PCI_REGION1: return PCI_0MEMORY1_ADDRESS_REMAP; | |
294 | case PCI_REGION2: return PCI_0MEMORY2_ADDRESS_REMAP; | |
295 | case PCI_REGION3: return PCI_0MEMORY3_ADDRESS_REMAP; | |
296 | } | |
297 | case PCI_HOST1: | |
298 | switch(region) { | |
299 | case PCI_IO: return PCI_1I_O_ADDRESS_REMAP; | |
300 | case PCI_REGION0: return PCI_1MEMORY0_ADDRESS_REMAP; | |
301 | case PCI_REGION1: return PCI_1MEMORY1_ADDRESS_REMAP; | |
302 | case PCI_REGION2: return PCI_1MEMORY2_ADDRESS_REMAP; | |
303 | case PCI_REGION3: return PCI_1MEMORY3_ADDRESS_REMAP; | |
304 | } | |
305 | } | |
306 | return PCI_0MEMORY0_ADDRESS_REMAP; | |
307 | } | |
308 | ||
309 | bool pciMapSpace(PCI_HOST host, PCI_REGION region, unsigned int remapBase, unsigned int bankBase,unsigned int bankLength) | |
310 | { | |
311 | unsigned int low=0xfff; | |
312 | unsigned int high=0x0; | |
313 | unsigned int regOffset=pciGetRegOffset(host, region); | |
314 | unsigned int remapOffset=pciGetRemapOffset(host, region); | |
315 | ||
316 | if(bankLength!=0) { | |
317 | low = (bankBase >> 20) & 0xfff; | |
318 | high=((bankBase+bankLength)>>20)-1; | |
319 | } | |
320 | ||
321 | GT_REG_WRITE(regOffset, low | (1<<24)); /* no swapping */ | |
322 | GT_REG_WRITE(regOffset+8, high); | |
323 | ||
324 | if(bankLength!=0) { /* must do AFTER writing maps */ | |
325 | GT_REG_WRITE(remapOffset, remapBase>>20); /* sorry, 32 bits only. | |
326 | dont support upper 32 | |
327 | in this driver */ | |
328 | } | |
329 | return true; | |
330 | } | |
331 | ||
332 | unsigned int pciGetSpaceBase(PCI_HOST host, PCI_REGION region) | |
333 | { | |
334 | unsigned int low; | |
335 | unsigned int regOffset=pciGetRegOffset(host, region); | |
336 | GT_REG_READ(regOffset,&low); | |
337 | return (low&0xfff)<<20; | |
338 | } | |
339 | ||
340 | unsigned int pciGetSpaceSize(PCI_HOST host, PCI_REGION region) | |
341 | { | |
342 | unsigned int low,high; | |
343 | unsigned int regOffset=pciGetRegOffset(host, region); | |
344 | GT_REG_READ(regOffset,&low); | |
345 | GT_REG_READ(regOffset+8,&high); | |
346 | high&=0xfff; | |
347 | low&=0xfff; | |
348 | if(high<=low) return 0; | |
349 | return (high+1-low)<<20; | |
350 | } | |
351 | ||
352 | /******************************************************************** | |
353 | * pciMapMemoryBank - Maps PCI_host memory bank "bank" for the slave. | |
354 | * | |
355 | * Inputs: base and size of PCI SCS | |
356 | *********************************************************************/ | |
357 | void pciMapMemoryBank(PCI_HOST host, MEMORY_BANK bank, unsigned int pciDramBase,unsigned int pciDramSize) | |
358 | { | |
8bde7f77 | 359 | pciDramBase = pciDramBase & 0xfffff000; |
c609719b | 360 | pciDramBase = pciDramBase | (pciReadConfigReg(host, |
8bde7f77 | 361 | PCI_SCS_0_BASE_ADDRESS + 4*bank,SELF) & 0x00000fff); |
c609719b WD |
362 | pciWriteConfigReg(host,PCI_SCS_0_BASE_ADDRESS + 4*bank,SELF,pciDramBase); |
363 | if(pciDramSize == 0) | |
8bde7f77 | 364 | pciDramSize ++; |
c609719b WD |
365 | GT_REG_WRITE(pci_scs_bank_size[host][bank], pciDramSize-1); |
366 | } | |
367 | ||
368 | ||
369 | /******************************************************************** | |
370 | * pciSetRegionFeatures - This function modifys one of the 8 regions with | |
371 | * feature bits given as an input. | |
372 | * - Be advised to check the spec before modifying them. | |
373 | * Inputs: PCI_PROTECT_REGION region - one of the eight regions. | |
374 | * unsigned int features - See file: pci.h there are defintion for those | |
375 | * region features. | |
376 | * unsigned int baseAddress - The region base Address. | |
377 | * unsigned int topAddress - The region top Address. | |
378 | * Returns: false if one of the parameters is erroneous true otherwise. | |
379 | *********************************************************************/ | |
380 | bool pciSetRegionFeatures(PCI_HOST host, PCI_ACCESS_REGIONS region,unsigned int features, | |
8bde7f77 | 381 | unsigned int baseAddress,unsigned int regionLength) |
c609719b WD |
382 | { |
383 | unsigned int accessLow; | |
384 | unsigned int accessHigh; | |
385 | unsigned int accessTop = baseAddress + regionLength; | |
386 | ||
387 | if(regionLength == 0) /* close the region. */ | |
388 | { | |
8bde7f77 WD |
389 | pciDisableAccessRegion(host, region); |
390 | return true; | |
c609719b WD |
391 | } |
392 | /* base Address is store is bits [11:0] */ | |
393 | accessLow = (baseAddress & 0xfff00000) >> 20; | |
394 | /* All the features are update according to the defines in pci.h (to be on | |
395 | the safe side we disable bits: [11:0] */ | |
396 | accessLow = accessLow | (features & 0xfffff000); | |
397 | /* write to the Low Access Region register */ | |
398 | GT_REG_WRITE( pci_access_control_base_0_low[host] + 0x10*region,accessLow); | |
399 | ||
400 | accessHigh = (accessTop & 0xfff00000) >> 20; | |
401 | ||
402 | /* write to the High Access Region register */ | |
403 | GT_REG_WRITE(pci_access_control_top_0[host] + 0x10*region,accessHigh - 1); | |
404 | return true; | |
405 | } | |
406 | ||
407 | /******************************************************************** | |
408 | * pciDisableAccessRegion - Disable The given Region by writing MAX size | |
409 | * to its low Address and MIN size to its high Address. | |
410 | * | |
411 | * Inputs: PCI_ACCESS_REGIONS region - The region we to be Disabled. | |
412 | * Returns: N/A. | |
413 | *********************************************************************/ | |
414 | void pciDisableAccessRegion(PCI_HOST host, PCI_ACCESS_REGIONS region) | |
415 | { | |
416 | /* writing back the registers default values. */ | |
417 | GT_REG_WRITE(pci_access_control_base_0_low[host] + 0x10*region,0x01001fff); | |
418 | GT_REG_WRITE(pci_access_control_top_0[host] + 0x10*region,0); | |
419 | } | |
420 | ||
421 | /******************************************************************** | |
422 | * pciArbiterEnable - Enables PCI-0`s Arbitration mechanism. | |
423 | * | |
424 | * Inputs: N/A | |
425 | * Returns: true. | |
426 | *********************************************************************/ | |
427 | bool pciArbiterEnable(PCI_HOST host) | |
428 | { | |
429 | unsigned int regData; | |
430 | ||
431 | GT_REG_READ(pci_arbiter_control[host],®Data); | |
432 | GT_REG_WRITE(pci_arbiter_control[host],regData | BIT31); | |
433 | return true; | |
434 | } | |
435 | ||
436 | /******************************************************************** | |
437 | * pciArbiterDisable - Disable PCI-0`s Arbitration mechanism. | |
438 | * | |
439 | * Inputs: N/A | |
440 | * Returns: true | |
441 | *********************************************************************/ | |
442 | bool pciArbiterDisable(PCI_HOST host) | |
443 | { | |
444 | unsigned int regData; | |
445 | ||
446 | GT_REG_READ(pci_arbiter_control[host],®Data); | |
447 | GT_REG_WRITE(pci_arbiter_control[host],regData & 0x7fffffff); | |
448 | return true; | |
449 | } | |
450 | ||
451 | /******************************************************************** | |
452 | * pciParkingDisable - Park on last option disable, with this function you can | |
453 | * disable the park on last mechanism for each agent. | |
454 | * disabling this option for all agents results parking | |
455 | * on the internal master. | |
456 | * | |
457 | * Inputs: PCI_AGENT_PARK internalAgent - parking Disable for internal agent. | |
458 | * PCI_AGENT_PARK externalAgent0 - parking Disable for external#0 agent. | |
459 | * PCI_AGENT_PARK externalAgent1 - parking Disable for external#1 agent. | |
460 | * PCI_AGENT_PARK externalAgent2 - parking Disable for external#2 agent. | |
461 | * PCI_AGENT_PARK externalAgent3 - parking Disable for external#3 agent. | |
462 | * PCI_AGENT_PARK externalAgent4 - parking Disable for external#4 agent. | |
463 | * PCI_AGENT_PARK externalAgent5 - parking Disable for external#5 agent. | |
464 | * Returns: true | |
465 | *********************************************************************/ | |
466 | bool pciParkingDisable(PCI_HOST host, PCI_AGENT_PARK internalAgent, | |
8bde7f77 WD |
467 | PCI_AGENT_PARK externalAgent0, |
468 | PCI_AGENT_PARK externalAgent1, | |
469 | PCI_AGENT_PARK externalAgent2, | |
470 | PCI_AGENT_PARK externalAgent3, | |
471 | PCI_AGENT_PARK externalAgent4, | |
472 | PCI_AGENT_PARK externalAgent5) | |
c609719b WD |
473 | { |
474 | unsigned int regData; | |
475 | unsigned int writeData; | |
476 | ||
477 | GT_REG_READ(pci_arbiter_control[host],®Data); | |
478 | writeData = (internalAgent << 14) + (externalAgent0 << 15) + \ | |
8bde7f77 WD |
479 | (externalAgent1 << 16) + (externalAgent2 << 17) + \ |
480 | (externalAgent3 << 18) + (externalAgent4 << 19) + \ | |
481 | (externalAgent5 << 20); | |
c609719b WD |
482 | regData = (regData & ~(0x7f<<14)) | writeData; |
483 | GT_REG_WRITE(pci_arbiter_control[host],regData); | |
484 | return true; | |
485 | } | |
486 | ||
487 | /******************************************************************** | |
488 | * pciSetRegionSnoopMode - This function modifys one of the 4 regions which | |
489 | * supports Cache Coherency in the PCI_n interface. | |
490 | * Inputs: region - One of the four regions. | |
491 | * snoopType - There is four optional Types: | |
492 | * 1. No Snoop. | |
493 | * 2. Snoop to WT region. | |
494 | * 3. Snoop to WB region. | |
495 | * 4. Snoop & Invalidate to WB region. | |
496 | * baseAddress - Base Address of this region. | |
497 | * regionLength - Region length. | |
498 | * Returns: false if one of the parameters is wrong otherwise return true. | |
499 | *********************************************************************/ | |
500 | bool pciSetRegionSnoopMode(PCI_HOST host, PCI_SNOOP_REGION region,PCI_SNOOP_TYPE snoopType, | |
8bde7f77 WD |
501 | unsigned int baseAddress, |
502 | unsigned int regionLength) | |
c609719b WD |
503 | { |
504 | unsigned int snoopXbaseAddress; | |
505 | unsigned int snoopXtopAddress; | |
506 | unsigned int data; | |
507 | unsigned int snoopHigh = baseAddress + regionLength; | |
508 | ||
509 | if( (region > PCI_SNOOP_REGION3) || (snoopType > PCI_SNOOP_WB) ) | |
8bde7f77 | 510 | return false; |
c609719b WD |
511 | snoopXbaseAddress = pci_snoop_control_base_0_low[host] + 0x10 * region; |
512 | snoopXtopAddress = pci_snoop_control_top_0[host] + 0x10 * region; | |
513 | if(regionLength == 0) /* closing the region */ | |
514 | { | |
8bde7f77 WD |
515 | GT_REG_WRITE(snoopXbaseAddress,0x0000ffff); |
516 | GT_REG_WRITE(snoopXtopAddress,0); | |
517 | return true; | |
c609719b WD |
518 | } |
519 | baseAddress = baseAddress & 0xfff00000; /* Granularity of 1MByte */ | |
520 | data = (baseAddress >> 20) | snoopType << 12; | |
521 | GT_REG_WRITE(snoopXbaseAddress,data); | |
522 | snoopHigh = (snoopHigh & 0xfff00000) >> 20; | |
523 | GT_REG_WRITE(snoopXtopAddress,snoopHigh - 1); | |
524 | return true; | |
525 | } | |
526 | ||
527 | /* | |
528 | * | |
529 | */ | |
530 | ||
531 | static int gt_read_config_dword(struct pci_controller *hose, | |
532 | pci_dev_t dev, | |
533 | int offset, u32* value) | |
534 | { | |
db2f721f | 535 | int bus = PCI_BUS(dev); |
8bde7f77 | 536 | |
db2f721f | 537 | if ((bus == local_buses[0]) || (bus == local_buses[1])){ |
8bde7f77 | 538 | *value = pciReadConfigReg((PCI_HOST) hose->cfg_addr, offset, |
db2f721f WD |
539 | PCI_DEV(dev)); |
540 | } else { | |
8bde7f77 | 541 | *value = pciOverBridgeReadConfigReg((PCI_HOST) hose->cfg_addr, |
db2f721f WD |
542 | offset, PCI_DEV(dev), bus); |
543 | } | |
544 | return 0; | |
c609719b WD |
545 | } |
546 | ||
547 | static int gt_write_config_dword(struct pci_controller *hose, | |
548 | pci_dev_t dev, | |
549 | int offset, u32 value) | |
550 | { | |
db2f721f WD |
551 | int bus = PCI_BUS(dev); |
552 | ||
553 | if ((bus == local_buses[0]) || (bus == local_buses[1])){ | |
8bde7f77 | 554 | pciWriteConfigReg((PCI_HOST)hose->cfg_addr, offset, |
db2f721f WD |
555 | PCI_DEV(dev), value); |
556 | } else { | |
8bde7f77 | 557 | pciOverBridgeWriteConfigReg((PCI_HOST)hose->cfg_addr, offset, |
db2f721f WD |
558 | PCI_DEV(dev), value, bus); |
559 | } | |
560 | return 0; | |
c609719b WD |
561 | } |
562 | ||
563 | /* | |
564 | * | |
565 | */ | |
566 | ||
567 | static void gt_setup_ide(struct pci_controller *hose, | |
568 | pci_dev_t dev, struct pci_config_table *entry) | |
569 | { | |
570 | static const int ide_bar[]={8,4,8,4,0,0}; | |
571 | u32 bar_response, bar_value; | |
572 | int bar; | |
573 | ||
574 | for (bar=0; bar<6; bar++) | |
575 | { | |
576 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar*4, 0x0); | |
577 | pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar*4, &bar_response); | |
578 | ||
579 | pciauto_region_allocate(bar_response & PCI_BASE_ADDRESS_SPACE_IO ? | |
580 | hose->pci_io : hose->pci_mem, ide_bar[bar], &bar_value); | |
581 | ||
582 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar*4, bar_value); | |
583 | } | |
584 | } | |
585 | ||
586 | static void gt_fixup_irq(struct pci_controller *hose, pci_dev_t dev) | |
587 | { | |
588 | unsigned char pin, irq; | |
589 | ||
590 | pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); | |
591 | ||
592 | if(pin == 1) { /* only allow INT A */ | |
593 | irq = pci_irq_swizzle[(PCI_HOST)hose->cfg_addr][PCI_DEV(dev)]; | |
594 | if(irq) | |
595 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); | |
596 | } | |
597 | } | |
598 | ||
599 | struct pci_config_table gt_config_table[] = { | |
600 | { PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE, | |
601 | PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, gt_setup_ide}, | |
602 | ||
603 | { } | |
604 | }; | |
605 | ||
606 | struct pci_controller pci0_hose = { | |
607 | fixup_irq: gt_fixup_irq, | |
608 | config_table: gt_config_table, | |
609 | }; | |
610 | ||
611 | struct pci_controller pci1_hose = { | |
612 | fixup_irq: gt_fixup_irq, | |
613 | config_table: gt_config_table, | |
614 | }; | |
615 | ||
616 | void | |
ad10dd9a | 617 | pci_init_board(void) |
c609719b WD |
618 | { |
619 | unsigned int command; | |
620 | ||
621 | pci0_hose.first_busno = 0; | |
622 | pci0_hose.last_busno = 0xff; | |
db2f721f | 623 | local_buses[0] = pci0_hose.first_busno; |
c609719b WD |
624 | /* PCI memory space */ |
625 | pci_set_region(pci0_hose.regions + 0, | |
626 | CFG_PCI0_0_MEM_SPACE, | |
627 | CFG_PCI0_0_MEM_SPACE, | |
628 | CFG_PCI0_MEM_SIZE, | |
629 | PCI_REGION_MEM); | |
630 | ||
631 | /* PCI I/O space */ | |
632 | pci_set_region(pci0_hose.regions + 1, | |
633 | CFG_PCI0_IO_SPACE_PCI, | |
634 | CFG_PCI0_IO_SPACE, | |
635 | CFG_PCI0_IO_SIZE, | |
636 | PCI_REGION_IO); | |
637 | ||
638 | pci_set_ops(&pci0_hose, | |
639 | pci_hose_read_config_byte_via_dword, | |
640 | pci_hose_read_config_word_via_dword, | |
641 | gt_read_config_dword, | |
642 | pci_hose_write_config_byte_via_dword, | |
643 | pci_hose_write_config_word_via_dword, | |
644 | gt_write_config_dword); | |
645 | ||
646 | pci0_hose.region_count = 2; | |
647 | ||
648 | pci0_hose.cfg_addr = (unsigned int*) PCI_HOST0; | |
649 | ||
650 | pci_register_hose(&pci0_hose); | |
651 | ||
652 | pciArbiterEnable(PCI_HOST0); | |
653 | pciParkingDisable(PCI_HOST0,1,1,1,1,1,1,1); | |
654 | ||
655 | command = pciReadConfigReg(PCI_HOST0, PCI_COMMAND, SELF); | |
656 | command |= PCI_COMMAND_MASTER; | |
657 | pciWriteConfigReg(PCI_HOST0, PCI_COMMAND, SELF, command); | |
658 | ||
659 | pci0_hose.last_busno = pci_hose_scan(&pci0_hose); | |
660 | ||
661 | command = pciReadConfigReg(PCI_HOST0, PCI_COMMAND, SELF); | |
662 | command |= PCI_COMMAND_MEMORY; | |
663 | pciWriteConfigReg(PCI_HOST0, PCI_COMMAND, SELF, command); | |
664 | ||
665 | pci1_hose.first_busno = pci0_hose.last_busno + 1; | |
666 | pci1_hose.last_busno = 0xff; | |
db2f721f WD |
667 | pci1_hose.current_busno = pci0_hose.current_busno; |
668 | local_buses[1] = pci1_hose.first_busno; | |
c609719b WD |
669 | |
670 | /* PCI memory space */ | |
671 | pci_set_region(pci1_hose.regions + 0, | |
672 | CFG_PCI1_0_MEM_SPACE, | |
673 | CFG_PCI1_0_MEM_SPACE, | |
674 | CFG_PCI1_MEM_SIZE, | |
675 | PCI_REGION_MEM); | |
676 | ||
677 | /* PCI I/O space */ | |
678 | pci_set_region(pci1_hose.regions + 1, | |
679 | CFG_PCI1_IO_SPACE_PCI, | |
680 | CFG_PCI1_IO_SPACE, | |
681 | CFG_PCI1_IO_SIZE, | |
682 | PCI_REGION_IO); | |
683 | ||
684 | pci_set_ops(&pci1_hose, | |
685 | pci_hose_read_config_byte_via_dword, | |
686 | pci_hose_read_config_word_via_dword, | |
687 | gt_read_config_dword, | |
688 | pci_hose_write_config_byte_via_dword, | |
689 | pci_hose_write_config_word_via_dword, | |
690 | gt_write_config_dword); | |
691 | ||
692 | pci1_hose.region_count = 2; | |
693 | ||
694 | pci1_hose.cfg_addr = (unsigned int*) PCI_HOST1; | |
695 | ||
696 | pci_register_hose(&pci1_hose); | |
697 | ||
698 | pciArbiterEnable(PCI_HOST1); | |
699 | pciParkingDisable(PCI_HOST1,1,1,1,1,1,1,1); | |
700 | ||
701 | command = pciReadConfigReg(PCI_HOST1, PCI_COMMAND, SELF); | |
702 | command |= PCI_COMMAND_MASTER; | |
703 | pciWriteConfigReg(PCI_HOST1, PCI_COMMAND, SELF, command); | |
704 | ||
705 | pci1_hose.last_busno = pci_hose_scan(&pci1_hose); | |
706 | ||
707 | command = pciReadConfigReg(PCI_HOST1, PCI_COMMAND, SELF); | |
708 | command |= PCI_COMMAND_MEMORY; | |
709 | pciWriteConfigReg(PCI_HOST1, PCI_COMMAND, SELF, command); | |
710 | } |