|
1 /* |
|
2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 #include "pci-ne.h" |
|
21 #include "../naviengine_pci.h" |
|
22 #include <naviengine_priv.h> |
|
23 #include <naviengine.h> |
|
24 |
|
25 |
|
26 _LIT(KTConfigSpace, "TConfigSpace"); |
|
27 TConfigSpace::TConfigSpace(TPciFunction& aFunction, DPciBridge& aBridge) |
|
28 :TAddrSpace(KCfgSpaceSize, KTConfigSpace), iFunction(aFunction), iBridge(aBridge) |
|
29 { |
|
30 } |
|
31 |
|
32 /** |
|
33 Read 1 byte from config space. Config space is 256 bytes long |
|
34 out of range access will fault the kernel. |
|
35 */ |
|
36 EXPORT_C TUint8 TConfigSpace::Read8(TUint32 aOffset) |
|
37 { |
|
38 CheckAccess(E1Byte, aOffset); |
|
39 |
|
40 return iBridge.ReadConfig8( |
|
41 iFunction.Bus(), |
|
42 iFunction.Device(), |
|
43 iFunction.Function(), |
|
44 aOffset |
|
45 ); |
|
46 } |
|
47 |
|
48 EXPORT_C TUint16 TConfigSpace::Read16(TUint32 aOffset) |
|
49 { |
|
50 CheckAccess(E2Byte, aOffset); |
|
51 |
|
52 return iBridge.ReadConfig16( |
|
53 iFunction.Bus(), |
|
54 iFunction.Device(), |
|
55 iFunction.Function(), |
|
56 aOffset |
|
57 ); |
|
58 } |
|
59 |
|
60 EXPORT_C TUint32 TConfigSpace::Read32(TUint32 aOffset) |
|
61 { |
|
62 CheckAccess(E4Byte, aOffset); |
|
63 |
|
64 return iBridge.ReadConfig32( |
|
65 iFunction.Bus(), |
|
66 iFunction.Device(), |
|
67 iFunction.Function(), |
|
68 aOffset |
|
69 ); |
|
70 } |
|
71 |
|
72 EXPORT_C void TConfigSpace::Write8(TUint32 aOffset, TUint8 aValue) |
|
73 { |
|
74 CheckAccess(E1Byte, aOffset); |
|
75 |
|
76 iBridge.WriteConfig8( |
|
77 iFunction.Bus(), |
|
78 iFunction.Device(), |
|
79 iFunction.Function(), |
|
80 aOffset, |
|
81 aValue |
|
82 ); |
|
83 } |
|
84 |
|
85 EXPORT_C void TConfigSpace::Write16(TUint32 aOffset, TUint16 aValue) |
|
86 { |
|
87 CheckAccess(E2Byte, aOffset); |
|
88 |
|
89 iBridge.WriteConfig16( |
|
90 iFunction.Bus(), |
|
91 iFunction.Device(), |
|
92 iFunction.Function(), |
|
93 aOffset, |
|
94 aValue |
|
95 ); |
|
96 } |
|
97 |
|
98 EXPORT_C void TConfigSpace::Write32(TUint32 aOffset, TUint32 aValue) |
|
99 { |
|
100 CheckAccess(E4Byte, aOffset); |
|
101 |
|
102 iBridge.WriteConfig32( |
|
103 iFunction.Bus(), |
|
104 iFunction.Device(), |
|
105 iFunction.Function(), |
|
106 aOffset, |
|
107 aValue |
|
108 ); |
|
109 } |
|
110 |
|
111 EXPORT_C void TConfigSpace::Modify8(TUint32 aOffset, TUint8 aClearMask, TUint8 aSetMask) |
|
112 { |
|
113 CheckAccess(E1Byte, aOffset); |
|
114 |
|
115 iBridge.ModifyConfig8( |
|
116 iFunction.Bus(), |
|
117 iFunction.Device(), |
|
118 iFunction.Function(), |
|
119 aOffset, |
|
120 aClearMask, |
|
121 aSetMask |
|
122 ); |
|
123 } |
|
124 |
|
125 EXPORT_C void TConfigSpace::Modify16(TUint32 aOffset, TUint16 aClearMask, TUint16 aSetMask) |
|
126 { |
|
127 CheckAccess(E2Byte, aOffset); |
|
128 |
|
129 iBridge.ModifyConfig16( |
|
130 iFunction.Bus(), |
|
131 iFunction.Device(), |
|
132 iFunction.Function(), |
|
133 aOffset, |
|
134 aClearMask, |
|
135 aSetMask |
|
136 ); |
|
137 } |
|
138 |
|
139 EXPORT_C void TConfigSpace::Modify32(TUint32 aOffset, TUint32 aClearMask, TUint32 aSetMask) |
|
140 { |
|
141 CheckAccess(E4Byte, aOffset); |
|
142 |
|
143 iBridge.ModifyConfig32( |
|
144 iFunction.Bus(), |
|
145 iFunction.Device(), |
|
146 iFunction.Function(), |
|
147 aOffset, |
|
148 aClearMask, |
|
149 aSetMask |
|
150 ); |
|
151 } |
|
152 |
|
153 DNaviEnginePciBridge::DNaviEnginePciBridge(TUint aBaseAddress, TUint32 aVirtualWindow) |
|
154 :DPciBridge(), iBaseAddr(aBaseAddress), |
|
155 iVirtualWindow(aVirtualWindow), |
|
156 iAllocator(KPciAddressSpaceSize), |
|
157 iMapMan(KNeBridgeNumberOfBars, iAllocator, iBaseAddr), |
|
158 iChunkMan(iMapMan), |
|
159 iVid(AsspRegister::Read16(iBaseAddr+KHoPciVid)), |
|
160 iDid(AsspRegister::Read16(iBaseAddr+KHoPciDid)) |
|
161 { |
|
162 } |
|
163 |
|
164 TInt DNaviEnginePciBridge::Initialise() |
|
165 { |
|
166 __KTRACE_OPT(KPCI, Kern::Printf("Initialising Naviengine bridge: Base address: %x", iBaseAddr)) ; |
|
167 InitialiseRegisters(); |
|
168 return SetupInterrupts(); |
|
169 } |
|
170 |
|
171 DNaviEnginePciBridge::~DNaviEnginePciBridge() |
|
172 { |
|
173 } |
|
174 |
|
175 /** |
|
176 Create a DPlatChunkHw which will be accessble to PCI devices under this bridge. |
|
177 |
|
178 @param aSize Amount of memory visible from PCI in bytes. |
|
179 This will be rounded up to the next power of 2 in kilobytes |
|
180 .eg 1K, 2K, 4K etc. @note The actual amount of memory allocated |
|
181 will always be a multiple of the page size (4K), but any excess |
|
182 will not be visible to the PCI bus. |
|
183 @param aPciAddress On success, will be a PCI address by which the chunk may be accessed |
|
184 @return |
|
185 - KErrNone - On Success |
|
186 - KErrInUse - aChunk was not NULL |
|
187 - KErrNotFound - All of Bridge's BARS have been used up. Free one with RemoveChunk |
|
188 - KErrArgument - aSize was less than 1. |
|
189 */ |
|
190 TInt DNaviEnginePciBridge::CreateChunk(DPlatChunkHw*& aChunk, TInt aSize, TUint aAttributes, TUint32& aPciAddress) |
|
191 { |
|
192 if(aChunk!=NULL) |
|
193 return KErrInUse; |
|
194 if(aSize<1) |
|
195 return KErrArgument; |
|
196 |
|
197 return iChunkMan.AddChunk(aChunk, aSize, aAttributes, aPciAddress); |
|
198 } |
|
199 |
|
200 /** |
|
201 Create a DChunk which will be accessble to PCI devices under this bridge. |
|
202 |
|
203 @param aSize Amount of memory to be allocated to chunk. |
|
204 This will be rounded up to at least the next power of 2 in kilobytes |
|
205 .eg 1K, 2K, 4K, 8k etc. |
|
206 @param aPciAddress On success, will be a PCI address by which the chunk may be accessed |
|
207 @return |
|
208 - KErrNone - On Success |
|
209 - KErrInUse - aChunk was not NULL |
|
210 - KErrNotFound - All of Bridge's BARS have been used up. Free one with RemoveChunk |
|
211 - KErrArgument - aSize was less than 1. |
|
212 */ |
|
213 TInt DNaviEnginePciBridge::CreateChunk(DChunk*& aChunk, TChunkCreateInfo &aAttributes, TUint aOffset, TUint aSize, TUint32& aPciAddress) |
|
214 { |
|
215 if(aChunk!=NULL) |
|
216 return KErrInUse; |
|
217 if(aSize<1) |
|
218 return KErrArgument; |
|
219 |
|
220 return iChunkMan.AddChunk(aChunk, aAttributes, aOffset, aSize, aPciAddress); |
|
221 } |
|
222 |
|
223 |
|
224 TInt DNaviEnginePciBridge::RemoveChunk(DPlatChunkHw* aChunk) |
|
225 { |
|
226 return iChunkMan.RemoveChunk(aChunk); |
|
227 } |
|
228 |
|
229 TInt DNaviEnginePciBridge::CreateMapping(TUint32 aPhysicalAddress, TInt aSize, TUint32& aPciAddress) |
|
230 { |
|
231 if(aSize<1) |
|
232 return KErrArgument; |
|
233 |
|
234 return iMapMan.CreateMapping(aPhysicalAddress, aSize, aPciAddress); |
|
235 } |
|
236 |
|
237 TInt DNaviEnginePciBridge::RemoveMapping(TUint32 aPhysicalAddress) |
|
238 { |
|
239 return iMapMan.RemoveMapping(aPhysicalAddress); |
|
240 } |
|
241 |
|
242 TInt DNaviEnginePciBridge::GetPciAddress(TUint32 aPhysicalAddress, TUint32& aPciAddress) |
|
243 { |
|
244 return iMapMan.GetPciAddress(aPhysicalAddress, aPciAddress); |
|
245 } |
|
246 |
|
247 TInt DNaviEnginePciBridge::GetPhysicalAddress(TUint32 aPciAddress, TUint32& aPhysicalAddress) |
|
248 { |
|
249 return iMapMan.GetPhysicalAddress(aPciAddress, aPhysicalAddress); |
|
250 } |
|
251 |
|
252 /** |
|
253 Attempt to access function at this location. If it exists then scan its |
|
254 bars to create required PCI memory space. |
|
255 Create and return a complete TPciFunction |
|
256 */ |
|
257 TPciFunction* DNaviEnginePciBridge::Function(TInt aBus, TInt aDevice, TInt aFunction) |
|
258 { |
|
259 const TUint32 val = ReadConfig32(aBus, aDevice, aFunction, 0x0); |
|
260 |
|
261 //the function does not exist. |
|
262 if(val == 0xFFFFFFFF) |
|
263 return NULL; |
|
264 |
|
265 const TInt16 vid=val&0xFFFF; |
|
266 TInt16 did=(val>>16)&0xFFFF; |
|
267 |
|
268 //don't give access to the bridge its self |
|
269 if(vid==iVid && did==iDid) |
|
270 return NULL; |
|
271 |
|
272 TPciFunction* func= new TPciFunction(aBus, aDevice, aFunction, vid, did, *this); |
|
273 if(NULL==func) |
|
274 return func; |
|
275 |
|
276 TAddrSpace& configSpace=*func->GetConfigSpace(); |
|
277 |
|
278 TInt r=KErrNone; |
|
279 //scan each of the bars |
|
280 for(TInt i=0; i<KPciNumberOfBars; ++i) |
|
281 { |
|
282 const TInt barOffset=KPciBar0+(4*i); |
|
283 const TUint32 size= ProbeBar(configSpace, barOffset); |
|
284 |
|
285 if(NULL==size) |
|
286 continue; |
|
287 |
|
288 //allocate pci address range |
|
289 TUint32 pciAddress=0; |
|
290 r=iAllocator.Allocate(pciAddress, size); |
|
291 if(r!=KErrNone) |
|
292 break; |
|
293 |
|
294 //tell the function what its address is. |
|
295 r = func->AddMemorySpace(size, pciAddress+iVirtualWindow, i); |
|
296 if(r!=KErrNone) |
|
297 break; |
|
298 |
|
299 //modify bar. |
|
300 configSpace.Write32(barOffset, pciAddress); |
|
301 } |
|
302 |
|
303 if(r==KErrNone) |
|
304 { |
|
305 configSpace.Modify16(KHoPciCmd, NULL, KHtPcicmd_Memen); |
|
306 return func; |
|
307 } |
|
308 else |
|
309 { |
|
310 delete func; |
|
311 return NULL; |
|
312 } |
|
313 |
|
314 } |
|
315 |
|
316 void DNaviEnginePciBridge::ConfigurationComplete() |
|
317 { |
|
318 //state that config is complete and allow subsequent master aborts |
|
319 //to trigger the error interrupt |
|
320 AsspRegister::Modify32(iBaseAddr+KHoPciCtrlH, NULL, KHtPciCtrlH_CnfigDone| KHtPciCtrlH_Mase); |
|
321 Interrupt::Enable(EIntPciInt); |
|
322 } |
|
323 |
|
324 |
|
325 void DNaviEnginePciBridge::ErrorPrint() |
|
326 { |
|
327 Kern::Printf("Pci Errors:"); |
|
328 |
|
329 Kern::Printf(" Status Register"); |
|
330 volatile TUint16 status=AsspRegister::Read16(iBaseAddr+KHoPciStatus); |
|
331 if(status & KHtPciStatus_ParityError) |
|
332 Kern::Printf(" Parity Error"); |
|
333 if(status & KHtPciStatus_SystemError) |
|
334 Kern::Printf(" System Error"); |
|
335 if(status & KHtPciStatus_MasterAbrtRcvd) |
|
336 Kern::Printf(" MasterAbrtRcvd"); |
|
337 if(status & KHtPciStatus_TargetAbrtRcvd) |
|
338 Kern::Printf(" TargetAbrtRcvd"); |
|
339 if(status & KHtPciStatus_DPErrorAsserted) |
|
340 Kern::Printf(" PERR# asserted"); |
|
341 |
|
342 Kern::Printf(" Err1 Register:"); |
|
343 volatile TUint32 error=AsspRegister::Read32(iBaseAddr+KHoError1); |
|
344 if(error & KHtError1_SystemError) |
|
345 Kern::Printf(" System Error"); |
|
346 if(error & KHtError1_AMEr) |
|
347 Kern::Printf(" AHB master error"); |
|
348 |
|
349 Kern::Printf(" PciCtrlHi Register"); |
|
350 |
|
351 volatile TUint32 pciCtrlH=AsspRegister::Read32(iBaseAddr+KHoPciCtrlH); |
|
352 if(pciCtrlH & KHtPciCtrlH_Aper) |
|
353 Kern::Printf(" Address Parity error"); |
|
354 if(pciCtrlH & KHtPciCtrlH_Dtep) |
|
355 Kern::Printf(" Discard time out"); |
|
356 if(pciCtrlH & KHtPciCtrlH_Dper) |
|
357 Kern::Printf(" Data parity error"); |
|
358 if(pciCtrlH & KHtPciCtrlH_Rlex) |
|
359 Kern::Printf(" Retry limit exceeded"); |
|
360 if(pciCtrlH & KHtPciCtrlH_Mabo) |
|
361 Kern::Printf(" Master abort"); |
|
362 if(pciCtrlH & KHtPciCtrlH_Tabo) |
|
363 Kern::Printf(" Target abort"); |
|
364 |
|
365 } |
|
366 /** |
|
367 @param aOffset A DWord index (32 bit) |
|
368 @return A value sutiable for writing to the bridge's CNFIG_ADDR register |
|
369 */ |
|
370 TCnfgAddr DNaviEnginePciBridge::MakeConfigAddress(TInt aBus, TInt aDevice, TInt aFunction, TUint aDwordOffset) |
|
371 { |
|
372 using namespace ConfigAddress; |
|
373 const TUint32 bus=(aBus<<KHsBus); |
|
374 const TUint32 device=(aDevice<<KHsDevice); |
|
375 const TUint32 function=(aFunction<<KHsFunction); |
|
376 const TUint32 offset=(aDwordOffset<<KHsOffset); |
|
377 |
|
378 __NK_ASSERT_DEBUG( (bus & (~KHmBus)) == NULL); |
|
379 __NK_ASSERT_DEBUG( (device & (~KHmDevice)) == NULL); |
|
380 __NK_ASSERT_DEBUG( (function & (~KHmFunction)) == NULL); |
|
381 __NK_ASSERT_DEBUG( (offset & (~KHmOffset)) == NULL); |
|
382 |
|
383 return (KHtCnfigEnable| |
|
384 (bus & KHmBus)| |
|
385 (device & KHmDevice)| |
|
386 (function & KHmFunction)| |
|
387 (offset & KHmOffset) |
|
388 ); |
|
389 } |
|
390 |
|
391 /** |
|
392 Probes the specified bar to see whether it is implemented, if so |
|
393 then return the amount of memory space required. |
|
394 |
|
395 @note Driver does not currently support devices which request IO-space |
|
396 or 64-bit bars. |
|
397 */ |
|
398 TUint DNaviEnginePciBridge::ProbeBar(TAddrSpace& aCs, TUint32 aBarOffset) |
|
399 { |
|
400 __KTRACE_OPT(KPCI, Kern::Printf("DNaviEnginePciBridge::ProbeBar Probing BAR at Offset %d", aBarOffset)); |
|
401 |
|
402 //ignore any writable bits in positions [0:2] |
|
403 //they shouldn't be writable but are for the NaviEngine host |
|
404 //bridge |
|
405 const TUint32 KHmIgnore= Bar::KHtMemSpaceType|Bar::KHmType|Bar::KHtPreFetchable; |
|
406 |
|
407 aCs.Write32(aBarOffset, 0x00000000); |
|
408 TUint32 initial= aCs.Read32(aBarOffset); |
|
409 aCs.Write32(aBarOffset, KMaxTUint32); |
|
410 TUint32 bar = aCs.Read32(aBarOffset); |
|
411 |
|
412 //reset after probing |
|
413 aCs.Write32(aBarOffset, 0x00000000); |
|
414 |
|
415 if( (bar&(~KHmIgnore)) == (initial&(~KHmIgnore)) ) |
|
416 { |
|
417 __KTRACE_OPT(KPCI, Kern::Printf(" Function doesn't implement BAR")); |
|
418 return NULL; |
|
419 } |
|
420 if(bar & Bar::KHtMemSpaceType) |
|
421 { |
|
422 __KTRACE_OPT(KPCI, Kern::Printf(" IOSpace is not supported") ); |
|
423 return NULL; |
|
424 } |
|
425 |
|
426 if(bar & Bar::KHmType ) |
|
427 { |
|
428 __KTRACE_OPT(KPCI, Kern::Printf(" Only support 32 bit address space") ); |
|
429 return NULL; |
|
430 } |
|
431 |
|
432 TUint size= (bar<<1)^(bar); |
|
433 __KTRACE_OPT(KPCI, Kern::Printf(" Address space: %08x bytes", size)); |
|
434 return size; |
|
435 } |
|
436 |
|
437 |
|
438 |
|
439 TUint8 DNaviEnginePciBridge::ReadConfig8(TInt aBus, TInt aDevice, TInt aFunction, TUint aOffset) const |
|
440 { |
|
441 const TUint dwordOffset = aOffset>>2; //divide by 4 |
|
442 const TUint byteOffset = aOffset%4; |
|
443 |
|
444 const TCnfgAddr location = MakeConfigAddress(aBus, aDevice, aFunction, dwordOffset); |
|
445 |
|
446 Wait(); |
|
447 AsspRegister::Write32(KHoCnfig_addr+iBaseAddr, location); |
|
448 volatile TUint8 value = AsspRegister::Read8(iBaseAddr+KHoCnfig_data+byteOffset); |
|
449 Signal(); |
|
450 return value; |
|
451 } |
|
452 |
|
453 TUint16 DNaviEnginePciBridge::ReadConfig16(TInt aBus, TInt aDevice, TInt aFunction, TUint aOffset) const |
|
454 { |
|
455 const TUint dwordOffset = aOffset>>2; //divide by 4 |
|
456 const TUint byteOffset = aOffset%4; |
|
457 |
|
458 const TCnfgAddr location = MakeConfigAddress(aBus, aDevice, aFunction, dwordOffset); |
|
459 |
|
460 Wait(); |
|
461 AsspRegister::Write32(KHoCnfig_addr+iBaseAddr, location); |
|
462 volatile TUint16 value = AsspRegister::Read16(iBaseAddr+KHoCnfig_data+byteOffset); |
|
463 Signal(); |
|
464 return value; |
|
465 } |
|
466 |
|
467 /** |
|
468 @param aOffset A byte index |
|
469 */ |
|
470 TUint32 DNaviEnginePciBridge::ReadConfig32(TInt aBus, TInt aDevice, TInt aFunction, TUint aOffset) const |
|
471 { |
|
472 TUint dwordOffset = aOffset>>2; //divide by 4 |
|
473 |
|
474 const TCnfgAddr location = MakeConfigAddress(aBus, aDevice, aFunction, dwordOffset); |
|
475 |
|
476 Wait(); |
|
477 AsspRegister::Write32(KHoCnfig_addr+iBaseAddr, location); |
|
478 volatile TInt32 value = AsspRegister::Read32(KHoCnfig_data+iBaseAddr); |
|
479 Signal(); |
|
480 return value; |
|
481 } |
|
482 |
|
483 void DNaviEnginePciBridge::WriteConfig8(TInt aBus, TInt aDevice, TInt aFunction, TUint aOffset, TUint8 aValue) |
|
484 { |
|
485 TUint dwordOffset = aOffset>>2; //divide by 4 |
|
486 const TUint byteOffset = aOffset%4; |
|
487 |
|
488 const TCnfgAddr location = MakeConfigAddress(aBus, aDevice, aFunction, dwordOffset); |
|
489 |
|
490 Wait(); |
|
491 AsspRegister::Write32(KHoCnfig_addr+iBaseAddr, location); |
|
492 AsspRegister::Write8(KHoCnfig_data+iBaseAddr+byteOffset, aValue); |
|
493 Signal(); |
|
494 } |
|
495 |
|
496 void DNaviEnginePciBridge::WriteConfig16(TInt aBus, TInt aDevice, TInt aFunction, TUint aOffset, TUint16 aValue) |
|
497 { |
|
498 TUint dwordOffset = aOffset>>2; //divide by 4 |
|
499 const TUint byteOffset = aOffset%4; |
|
500 |
|
501 const TCnfgAddr location = MakeConfigAddress(aBus, aDevice, aFunction, dwordOffset); |
|
502 |
|
503 Wait(); |
|
504 AsspRegister::Write32(KHoCnfig_addr+iBaseAddr, location); |
|
505 AsspRegister::Write16(KHoCnfig_data+iBaseAddr+byteOffset, aValue); |
|
506 Signal(); |
|
507 } |
|
508 |
|
509 /** |
|
510 @param aOffset A byte index |
|
511 */ |
|
512 void DNaviEnginePciBridge::WriteConfig32(TInt aBus, TInt aDevice, TInt aFunction, TUint aOffset, TUint32 aValue) |
|
513 { |
|
514 //__KTRACE_OPT(KPCI, Kern::Printf("PCI: WriteConfig32: %x:%x:%x os=%x, val=%x ", aBus,aDevice, aFunction, aOffset, aValue)); |
|
515 TUint dwordOffset = aOffset>>2; //divide by 4 |
|
516 const TCnfgAddr location = MakeConfigAddress(aBus, aDevice, aFunction, dwordOffset); |
|
517 |
|
518 Wait(); |
|
519 AsspRegister::Write32(KHoCnfig_addr+iBaseAddr, location); |
|
520 AsspRegister::Write32(KHoCnfig_data+iBaseAddr, aValue); |
|
521 Signal(); |
|
522 } |
|
523 |
|
524 void DNaviEnginePciBridge::ModifyConfig8(TInt aBus, TInt aDevice, TInt aFunction, TUint aOffset, TUint8 aClearMask, TUint8 aSetMask) |
|
525 { |
|
526 //__KTRACE_OPT(KPCI, Kern::Printf("PCI: ModifyConfig32: %x:%x:%x os=%x, clear=%x, set=%x ",aBus,aDevice, aFunction, aOffset, aClearMask, aSetMask)); |
|
527 TUint dwordOffset = aOffset>>2; //divide by 4 (and trunctate) |
|
528 const TUint byteOffset = aOffset%4; |
|
529 |
|
530 const TCnfgAddr location = MakeConfigAddress(aBus, aDevice, aFunction, dwordOffset); |
|
531 |
|
532 Wait(); |
|
533 AsspRegister::Write32(KHoCnfig_addr+iBaseAddr, location); |
|
534 AsspRegister::Modify8(KHoCnfig_data+iBaseAddr+byteOffset, aClearMask, aSetMask); |
|
535 Signal(); |
|
536 } |
|
537 |
|
538 void DNaviEnginePciBridge::ModifyConfig16(TInt aBus, TInt aDevice, TInt aFunction, TUint aOffset, TUint16 aClearMask, TUint16 aSetMask) |
|
539 { |
|
540 //__KTRACE_OPT(KPCI, Kern::Printf("PCI: ModifyConfig32: %x:%x:%x os=%x, clear=%x, set=%x ",aBus,aDevice, aFunction, aOffset, aClearMask, aSetMask)); |
|
541 TUint dwordOffset = aOffset>>2; //divide by 4 (and trunctate) |
|
542 const TUint byteOffset = aOffset%4; |
|
543 |
|
544 const TCnfgAddr location = MakeConfigAddress(aBus, aDevice, aFunction, dwordOffset); |
|
545 |
|
546 Wait(); |
|
547 AsspRegister::Write32(KHoCnfig_addr+iBaseAddr, location); |
|
548 AsspRegister::Modify16(KHoCnfig_data+iBaseAddr+byteOffset, aClearMask, aSetMask); |
|
549 Signal(); |
|
550 } |
|
551 |
|
552 void DNaviEnginePciBridge::ModifyConfig32(TInt aBus, TInt aDevice, TInt aFunction, TUint aOffset, TUint32 aClearMask, TUint32 aSetMask) |
|
553 { |
|
554 //__KTRACE_OPT(KPCI, Kern::Printf("PCI: ModifyConfig32: %x:%x:%x os=%x, clear=%x, set=%x ",aBus,aDevice, aFunction, aOffset, aClearMask, aSetMask)); |
|
555 TUint dwordOffset = aOffset>>2; //divide by 4 (and trunctate) |
|
556 |
|
557 const TCnfgAddr location = MakeConfigAddress(aBus, aDevice, aFunction, dwordOffset); |
|
558 |
|
559 Wait(); |
|
560 AsspRegister::Write32(KHoCnfig_addr+iBaseAddr, location); |
|
561 AsspRegister::Modify32(KHoCnfig_data+iBaseAddr, aClearMask, aSetMask); |
|
562 Signal(); |
|
563 } |
|
564 |
|
565 void DNaviEnginePciBridge::InitialiseRegisters() |
|
566 { |
|
567 ClearRegisters(); |
|
568 |
|
569 //make the bridge a PCI master and respond as a target |
|
570 AsspRegister::Modify16(iBaseAddr+KHoPciCmd, 0x0, KHtPcicmd_Bmasen|KHtPcicmd_Memen|KHtPcicmd_Peren|KHtPcicmd_Seren); |
|
571 |
|
572 //set up inbound access to PCI through window 1. |
|
573 const TUint32 window1Register = |
|
574 0| //window points to address 0 of PCI |
|
575 (0x13<<Initiator::KHsA2PCAMask)| //modify incomming AHB address above 8k |
|
576 (0x3<<Initiator::KHsType)| //incomming accesses will perform memory read/memory write |
|
577 0x1; //enable incomming address conversion |
|
578 AsspRegister::Write32(iBaseAddr+Initiator::KHoReg1, window1Register); |
|
579 |
|
580 AsspRegister::Write32(iBaseAddr+KHoBarEnable, 0); //disable all BARs, don't yet want access from PCI to AHB |
|
581 |
|
582 AsspRegister::Modify32(iBaseAddr+KHoPciCtrlH ,NULL, |
|
583 KHtPciCtrlH_Aerse| |
|
584 KHtPciCtrlH_Dtimse| |
|
585 KHtPciCtrlH_Perse| |
|
586 KHtPciCtrlH_Rtyse| |
|
587 KHtPciCtrlH_Tase |
|
588 ); |
|
589 //report errors from PCI bus to AHB64PCI_ERR pin |
|
590 //report errror on AHB to AHB64PCI_ERR pin |
|
591 AsspRegister::Modify32(iBaseAddr+KHoError1, NULL, |
|
592 KHtError1_PEEn| |
|
593 KHtError1_AMEn |
|
594 ); |
|
595 |
|
596 } |
|
597 |
|
598 void DNaviEnginePciBridge::ClearRegisters() |
|
599 { |
|
600 ClearErrors(); |
|
601 |
|
602 AsspRegister::Modify16(iBaseAddr+KHoPciCmd, |
|
603 KHtPcicmd_Bmasen| |
|
604 KHtPcicmd_Memen| |
|
605 KHtPcicmd_Peren| |
|
606 KHtPcicmd_Seren, |
|
607 NULL); |
|
608 |
|
609 AsspRegister::Modify32(iBaseAddr+KHoPciCtrlH , |
|
610 KHtPciCtrlH_CnfigDone| |
|
611 KHtPciCtrlH_Aerse| |
|
612 KHtPciCtrlH_Dtimse| |
|
613 KHtPciCtrlH_Perse| |
|
614 KHtPciCtrlH_Rtyse| |
|
615 KHtPciCtrlH_Mase| |
|
616 KHtPciCtrlH_Tase, |
|
617 NULL |
|
618 ); |
|
619 |
|
620 AsspRegister::Modify32(iBaseAddr+KHoError1, |
|
621 KHtError1_PEEn| |
|
622 KHtError1_AMEn, |
|
623 NULL |
|
624 ); |
|
625 |
|
626 AsspRegister::Write32(KHoCnfig_addr+iBaseAddr, 0x0); |
|
627 |
|
628 AsspRegister::Write32(iBaseAddr+Initiator::KHoReg1, 0x0); |
|
629 AsspRegister::Write32(iBaseAddr+Initiator::KHoReg2, 0x0); |
|
630 } |
|
631 |
|
632 //Clear latched bits by wriring 1 to them |
|
633 void DNaviEnginePciBridge::ClearErrors() |
|
634 { |
|
635 AsspRegister::Modify16(iBaseAddr+KHoPciStatus, NULL, |
|
636 KHtPciStatus_ParityError| |
|
637 KHtPciStatus_SystemError| |
|
638 KHtPciStatus_MasterAbrtRcvd| |
|
639 KHtPciStatus_TargetAbrtRcvd| |
|
640 KHtPciStatus_DPErrorAsserted |
|
641 ); |
|
642 |
|
643 AsspRegister::Modify32(iBaseAddr+KHoError1, NULL, |
|
644 KHtError1_SystemError| |
|
645 KHtError1_AMEr |
|
646 ); |
|
647 |
|
648 AsspRegister::Modify32(iBaseAddr+KHoPciCtrlH, NULL, |
|
649 KHtPciCtrlH_Aper| |
|
650 KHtPciCtrlH_Dtep| |
|
651 KHtPciCtrlH_Dper| |
|
652 KHtPciCtrlH_Rlex| |
|
653 KHtPciCtrlH_Mabo| |
|
654 KHtPciCtrlH_Tabo |
|
655 ); |
|
656 |
|
657 } |
|
658 |
|
659 |
|
660 TInt DNaviEnginePciBridge::SetupInterrupts() |
|
661 { |
|
662 __KTRACE_OPT(KPCI, Kern::Printf("DNaviEnginePciBridge: SetupInterrupts()")); |
|
663 TInt r = KErrNone; |
|
664 |
|
665 __KTRACE_OPT(KPCI, Kern::Printf(" Binding EIntPciPErrB")); |
|
666 r = Interrupt::Bind(EIntPciPErrB, ParityErrorISR, this); |
|
667 __KTRACE_OPT(KPCI, Kern::Printf(" r=%d", r)); |
|
668 |
|
669 __KTRACE_OPT(KPCI, Kern::Printf(" Binding EIntPciSErrB")); |
|
670 r = Interrupt::Bind(EIntPciSErrB, SystemErrorISR, this); |
|
671 __KTRACE_OPT(KPCI, Kern::Printf(" r=%d", r)); |
|
672 |
|
673 __KTRACE_OPT(KPCI, Kern::Printf(" Binding EIntPciInt")); |
|
674 r = Interrupt::Bind(EIntPciInt, PciISR, this); |
|
675 __KTRACE_OPT(KPCI, Kern::Printf(" r=%d", r)); |
|
676 |
|
677 __KTRACE_OPT(KPCI, Kern::Printf(" Enabling EIntPciPErrB")); |
|
678 r = Interrupt::Enable(EIntPciPErrB); |
|
679 __KTRACE_OPT(KPCI, Kern::Printf(" r=%d", r)); |
|
680 |
|
681 __KTRACE_OPT(KPCI, Kern::Printf(" Enabling EIntPciSErrB")); |
|
682 r = Interrupt::Enable(EIntPciSErrB); |
|
683 __KTRACE_OPT(KPCI, Kern::Printf(" r=%d", r)); |
|
684 |
|
685 __KTRACE_OPT(KPCI, Kern::Printf(" Enabling EIntPciInt")); |
|
686 Interrupt::Clear(EIntPciInt); |
|
687 //r = Interrupt::Enable(EIntPciInt); |
|
688 __KTRACE_OPT(KPCI, Kern::Printf(" r=%d", r)); |
|
689 return r; |
|
690 } |
|
691 |
|
692 void DNaviEnginePciBridge::ParityErrorISR(void* aP) |
|
693 { |
|
694 Interrupt::Clear(EIntPciPErrB); |
|
695 Kern::Fault("PCI Parity error",0); |
|
696 } |
|
697 |
|
698 void DNaviEnginePciBridge::SystemErrorISR(void* aP) |
|
699 { |
|
700 Interrupt::Clear(EIntPciSErrB); |
|
701 Kern::Fault("PCI System error",0); |
|
702 } |
|
703 |
|
704 /** |
|
705 This interrupt is raised when a bus error has occured, if the |
|
706 appropriate bit has been set (KHtPciCtrlH_Mase). |
|
707 It will also be raised if a peripheral uses one of the |
|
708 native PCI interrupt lines - but this not yet supported. |
|
709 */ |
|
710 void DNaviEnginePciBridge::PciISR(void* aP) |
|
711 { |
|
712 Interrupt::Clear(EIntPciInt); |
|
713 DNaviEnginePciBridge* bridge = static_cast<DNaviEnginePciBridge*>(aP); |
|
714 __KTRACE_OPT(KPCI, |
|
715 Kern::Printf("Pci interrupt line: Bridge Base address 0x%08x",bridge->iBaseAddr); |
|
716 bridge->ErrorPrint(); |
|
717 ); |
|
718 |
|
719 volatile TUint16 status=AsspRegister::Read16((bridge->iBaseAddr)+KHoPciStatus); |
|
720 if(status & KHtPciStatus_SystemError) |
|
721 { |
|
722 Kern::Fault("PCI System Error: Fatal",0); |
|
723 } |
|
724 bridge->ClearErrors(); |
|
725 } |
|
726 |
|
727 // |
|
728 // TNaviEngineChunkCleanup // |
|
729 // |
|
730 |
|
731 TNaviEngineChunkCleanup::TNaviEngineChunkCleanup(TChunkManager& aChunkMan, TUint32 aPhysicalAddress) |
|
732 :TChunkCleanup(), iChunkMan(aChunkMan), iPhysicalAddress(aPhysicalAddress) |
|
733 { |
|
734 } |
|
735 |
|
736 TNaviEngineChunkCleanup::~TNaviEngineChunkCleanup() |
|
737 { |
|
738 } |
|
739 |
|
740 void TNaviEngineChunkCleanup::Destroy() |
|
741 { |
|
742 iChunkMan.RemoveChunk(iPhysicalAddress); |
|
743 } |
|
744 |
|
745 |
|
746 DECLARE_STANDARD_EXTENSION() |
|
747 { |
|
748 __KTRACE_OPT(KEXTENSION, Kern::Printf("Pci Extension starting...")); |
|
749 |
|
750 DPciBridge* internBridge = new DNaviEnginePciBridge(KHwPciBridgeUsb, KHwUsbHWindow); |
|
751 |
|
752 if(internBridge == NULL) |
|
753 return KErrNoMemory; |
|
754 |
|
755 TInt r = internBridge->Initialise(); |
|
756 if(r !=KErrNone) |
|
757 return r; |
|
758 |
|
759 r = internBridge->Register(); |
|
760 if(r !=KErrNone) |
|
761 { |
|
762 delete internBridge; |
|
763 return r; |
|
764 } |
|
765 |
|
766 r = Pci::Enumerate(); |
|
767 return r; |
|
768 } |
|
769 |
|
770 |
|
771 |
|
772 |
|
773 |