1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
1 // Copyright (c) 2004-2010 Nokia Corporation and/or its subsidiary(-ies). |
2 // All rights reserved. |
2 // All rights reserved. |
3 // This component and the accompanying materials are made available |
3 // This component and the accompanying materials are made available |
4 // under the terms of the License "Eclipse Public License v1.0" |
4 // under the terms of the License "Eclipse Public License v1.0" |
5 // which accompanies this distribution, and is available |
5 // which accompanies this distribution, and is available |
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
19 |
19 |
20 #include <kernel/kern_priv.h> |
20 #include <kernel/kern_priv.h> |
21 #include <template_assp.h> // /assp/template_assp/ |
21 #include <template_assp.h> // /assp/template_assp/ |
22 |
22 |
23 #include <drivers/dma.h> |
23 #include <drivers/dma.h> |
24 #include <drivers/dma_hai.h> |
|
25 |
24 |
26 |
25 |
27 // Debug support |
26 // Debug support |
28 static const char KDmaPanicCat[] = "DMA PSL - " __FILE__; |
27 static const char KDmaPanicCat[] = "DMA PSL - " __FILE__; |
29 |
28 |
30 static const TInt KMaxTransferLen = 0x1FE0; // max transfer length for this DMAC |
29 static const TInt KMaxTransferLen = 0x1FE0; // max transfer length for this DMAC |
31 static const TInt KMemAlignMask = 7; // memory addresses passed to DMAC must be multiple of 8 |
30 static const TInt KMemAlignMask = 7; // memory addresses passed to DMAC must be multiple of 8 |
32 static const TInt KChannelCount = 16; // we got 16 channels |
31 static const TInt KChannelCount = 16; // we got 16 channels |
33 static const TInt KDesCount = 160; // Initial DMA descriptor count |
32 static const TInt KDesCount = 1024; // DMA descriptor count |
34 |
33 |
35 |
34 |
36 class TDmaDesc |
35 class TDmaDesc |
37 // |
36 // |
38 // Hardware DMA descriptor |
37 // Hardware DMA descriptor |
109 { |
88 { |
110 return ((TLinAddr)aDes & 0xF) == 0; |
89 return ((TLinAddr)aDes & 0xF) == 0; |
111 } |
90 } |
112 |
91 |
113 |
92 |
114 static TUint32 DmaCmdReg(TUint aCount, TUint aFlags, TUint32 aSrcPslInfo, TUint32 aDstPslInfo) |
93 static TUint32 DcmdReg(TInt aCount, TUint aFlags, TUint32 aPslInfo) |
115 // |
94 // |
116 // Returns value to set in DMA command register or in descriptor command field. |
95 // Returns value to set in DMA command register or in descriptor command field. |
117 // |
96 // |
118 { |
97 { |
119 // TO DO: Construct CMD word from input values. |
98 // TO DO: Construct CMD word from input values. |
120 // The return value should reflect the actual control word. |
99 // The return value should reflect the actual control word. |
121 return (aCount | aFlags | aSrcPslInfo | aDstPslInfo); |
100 return (aCount | aFlags | aPslInfo); |
122 } |
101 } |
123 |
102 |
124 |
103 |
125 ////////////////////////////////////////////////////////////////////////////// |
104 ////////////////////////////////////////////////////////////////////////////// |
126 // Derived Channel (Scatter/Gather) |
105 // Derived Channel (Scatter/Gather) |
143 public: |
122 public: |
144 TTemplateDmac(); |
123 TTemplateDmac(); |
145 TInt Create(); |
124 TInt Create(); |
146 private: |
125 private: |
147 // from TDmac (PIL pure virtual) |
126 // from TDmac (PIL pure virtual) |
|
127 virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr); |
148 virtual void StopTransfer(const TDmaChannel& aChannel); |
128 virtual void StopTransfer(const TDmaChannel& aChannel); |
149 virtual TBool IsIdle(const TDmaChannel& aChannel); |
129 virtual TBool IsIdle(const TDmaChannel& aChannel); |
150 virtual TUint MaxTransferLength(TDmaChannel& aChannel, TUint aSrcFlags, |
130 virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); |
151 TUint aDstFlags, TUint32 aPslInfo); |
131 virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); |
152 virtual TUint AddressAlignMask(TDmaChannel& aChannel, TUint aSrcFlags, |
|
153 TUint aDstFlags, TUint32 aPslInfo); |
|
154 // from TDmac (PIL virtual) |
132 // from TDmac (PIL virtual) |
155 virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr); |
133 virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, |
156 virtual TInt InitHwDes(const SDmaDesHdr& aHdr, const TDmaTransferArgs& aTransferArgs); |
134 TUint aFlags, TUint32 aPslInfo, TUint32 aCookie); |
157 virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr); |
135 virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr); |
158 virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, |
136 virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, |
159 const SDmaDesHdr& aNewHdr); |
137 const SDmaDesHdr& aNewHdr); |
160 virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr); |
138 virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr); |
161 // other |
139 // other |
171 static TTemplateDmac Controller; |
149 static TTemplateDmac Controller; |
172 |
150 |
173 |
151 |
174 const TDmac::SCreateInfo TTemplateDmac::KInfo = |
152 const TDmac::SCreateInfo TTemplateDmac::KInfo = |
175 { |
153 { |
176 ETrue, // iCapsHwDes |
154 KChannelCount, |
177 KDesCount, // iDesCount |
155 KDesCount, |
178 sizeof(TDmaDesc), // iDesSize |
156 TDmac::KCapsBitHwDes, |
179 EMapAttrSupRw | EMapAttrFullyBlocking // iDesChunkAttribs |
157 sizeof(TDmaDesc), |
|
158 EMapAttrSupRw | EMapAttrFullyBlocking |
180 }; |
159 }; |
181 |
160 |
182 |
161 |
183 TTemplateDmac::TTemplateDmac() |
162 TTemplateDmac::TTemplateDmac() |
184 // |
163 // |
199 __DMA_ASSERTA(ReserveSetOfDes(KChannelCount) == KErrNone); |
178 __DMA_ASSERTA(ReserveSetOfDes(KChannelCount) == KErrNone); |
200 for (TInt i=0; i < KChannelCount; ++i) |
179 for (TInt i=0; i < KChannelCount; ++i) |
201 { |
180 { |
202 TDmaDesc* pD = HdrToHwDes(*iFreeHdr); |
181 TDmaDesc* pD = HdrToHwDes(*iFreeHdr); |
203 iChannels[i].iTmpDes = pD; |
182 iChannels[i].iTmpDes = pD; |
204 iChannels[i].iTmpDesPhysAddr = HwDesLinToPhys(pD); |
183 iChannels[i].iTmpDesPhysAddr = DesLinToPhys(pD); |
205 iFreeHdr = iFreeHdr->iNext; |
184 iFreeHdr = iFreeHdr->iNext; |
206 } |
185 } |
207 r = Interrupt::Bind(EAsspIntIdDma, Isr, this); |
186 r = Interrupt::Bind(EAsspIntIdDma, Isr, this); |
208 if (r == KErrNone) |
187 if (r == KErrNone) |
209 { |
188 { |
263 |
242 |
264 return ETrue; |
243 return ETrue; |
265 } |
244 } |
266 |
245 |
267 |
246 |
268 TUint TTemplateDmac::MaxTransferLength(TDmaChannel& /*aChannel*/, TUint /*aSrcFlags*/, |
247 TInt TTemplateDmac::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) |
269 TUint /*aDstFlags*/, TUint32 /*aPslInfo*/) |
248 // |
270 // |
249 // Returns the maximum transfer size for a given transfer. |
271 // Returns the maximum transfer length in bytes for a given transfer. |
|
272 // |
250 // |
273 { |
251 { |
274 // TO DO: Determine the proper return value, based on the arguments. |
252 // TO DO: Determine the proper return value, based on the arguments. |
275 |
253 |
276 // For instance: |
254 // For instance: |
277 return KMaxTransferLen; |
255 return KMaxTransferLen; |
278 } |
256 } |
279 |
257 |
280 |
258 |
281 TUint TTemplateDmac::AddressAlignMask(TDmaChannel& aChannel, TUint /*aSrcFlags*/, |
259 TUint TTemplateDmac::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) |
282 TUint /*aDstFlags*/, TUint32 /*aPslInfo*/) |
|
283 // |
260 // |
284 // Returns the memory buffer alignment restrictions mask for a given transfer. |
261 // Returns the memory buffer alignment restrictions mask for a given transfer. |
285 // |
262 // |
286 { |
263 { |
287 // TO DO: Determine the proper return value, based on the arguments. |
264 // TO DO: Determine the proper return value, based on the arguments. |
289 // For instance: |
266 // For instance: |
290 return KMemAlignMask; |
267 return KMemAlignMask; |
291 } |
268 } |
292 |
269 |
293 |
270 |
294 TInt TTemplateDmac::InitHwDes(const SDmaDesHdr& aHdr, const TDmaTransferArgs& aTransferArgs) |
271 void TTemplateDmac::InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, |
|
272 TUint aFlags, TUint32 aPslInfo, TUint32 /*aCookie*/) |
295 // |
273 // |
296 // Sets up (from a passed in request) the descriptor with that fragment's |
274 // Sets up (from a passed in request) the descriptor with that fragment's |
297 // source and destination address, the fragment size, and the (driver/DMA |
275 // source and destination address, the fragment size, and the (driver/DMA |
298 // controller) specific transfer parameters (mem/peripheral, burst size, |
276 // controller) specific transfer parameters (mem/peripheral, burst size, |
299 // transfer width). |
277 // transfer width). |
304 __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD)); |
282 __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD)); |
305 |
283 |
306 // Unaligned descriptor? Bug in generic layer! |
284 // Unaligned descriptor? Bug in generic layer! |
307 __DMA_ASSERTD(IsHwDesAligned(pD)); |
285 __DMA_ASSERTD(IsHwDesAligned(pD)); |
308 |
286 |
309 const TDmaTransferConfig& src = aTransferArgs.iSrcConfig; |
287 pD->iSrcAddr = (aFlags & KDmaPhysAddrSrc) ? aSrc : Epoc::LinearToPhysical(aSrc); |
310 const TDmaTransferConfig& dst = aTransferArgs.iDstConfig; |
288 __DMA_ASSERTD(pD->iSrcAddr != KPhysAddrInvalid); |
311 pD->iSrcAddr = (src.iFlags & KDmaPhysAddr) ? src.iAddr : Epoc::LinearToPhysical(src.iAddr); |
289 pD->iDestAddr = (aFlags & KDmaPhysAddrDest) ? aDest : Epoc::LinearToPhysical(aDest); |
312 pD->iDestAddr = (dst.iFlags & KDmaPhysAddr) ? dst.iAddr : Epoc::LinearToPhysical(dst.iAddr); |
290 __DMA_ASSERTD(pD->iDestAddr != KPhysAddrInvalid); |
313 pD->iCmd = DmaCmdReg(aTransferArgs.iTransferCount, aTransferArgs.iFlags, |
291 pD->iCmd = DcmdReg(aCount, aFlags, aPslInfo); |
314 src.iPslTargetInfo, dst.iPslTargetInfo); |
|
315 pD->iDescAddr = TDmaDesc::KStopBitMask; |
292 pD->iDescAddr = TDmaDesc::KStopBitMask; |
316 |
|
317 return KErrNone; |
|
318 } |
293 } |
319 |
294 |
320 |
295 |
321 void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr) |
296 void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr) |
322 // |
297 // |
332 // Unaligned descriptor? Bug in generic layer! |
307 // Unaligned descriptor? Bug in generic layer! |
333 __DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN)); |
308 __DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN)); |
334 |
309 |
335 // TO DO: Modify pD->iCmd so that no end-of-transfer interrupt gets raised any longer. |
310 // TO DO: Modify pD->iCmd so that no end-of-transfer interrupt gets raised any longer. |
336 |
311 |
337 pD->iDescAddr = HwDesLinToPhys(pN); |
312 pD->iDescAddr = DesLinToPhys(pN); |
338 } |
313 } |
339 |
314 |
340 |
315 |
341 void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, |
316 void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, |
342 const SDmaDesHdr& aNewHdr) |
317 const SDmaDesHdr& aNewHdr) |
352 __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X", |
327 __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X", |
353 i, pL, pN)); |
328 i, pL, pN)); |
354 // Unaligned descriptor? Bug in generic layer! |
329 // Unaligned descriptor? Bug in generic layer! |
355 __DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN)); |
330 __DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN)); |
356 |
331 |
357 TPhysAddr newPhys = HwDesLinToPhys(pN); |
332 TPhysAddr newPhys = DesLinToPhys(pN); |
358 |
333 |
359 const TInt irq = NKern::DisableAllInterrupts(); |
334 const TInt irq = NKern::DisableAllInterrupts(); |
360 StopTransfer(aChannel); |
335 StopTransfer(aChannel); |
361 |
336 |
362 pL->iDescAddr = newPhys; |
337 pL->iDescAddr = newPhys; |
396 { |
371 { |
397 TTemplateDmac& me = *static_cast<TTemplateDmac*>(aThis); |
372 TTemplateDmac& me = *static_cast<TTemplateDmac*>(aThis); |
398 |
373 |
399 // TO DO: Implement the behaviour described above, call HandleIsr(). |
374 // TO DO: Implement the behaviour described above, call HandleIsr(). |
400 |
375 |
401 HandleIsr(me.iChannels[5], EDmaCallbackRequestCompletion, ETrue); // Example |
376 HandleIsr(me.iChannels[5], 0); // Example |
402 |
377 |
403 } |
378 } |
404 |
379 |
405 |
380 |
406 inline TDmaDesc* TTemplateDmac::HdrToHwDes(const SDmaDesHdr& aHdr) |
381 inline TDmaDesc* TTemplateDmac::HdrToHwDes(const SDmaDesHdr& aHdr) |
414 |
389 |
415 ////////////////////////////////////////////////////////////////////////////// |
390 ////////////////////////////////////////////////////////////////////////////// |
416 // Channel Opening/Closing (Channel Allocator) |
391 // Channel Opening/Closing (Channel Allocator) |
417 ////////////////////////////////////////////////////////////////////////////// |
392 ////////////////////////////////////////////////////////////////////////////// |
418 |
393 |
419 TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId, TBool /*aDynChannel*/, TUint /*aPriority*/) |
394 TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId) |
420 // |
395 // |
421 // |
396 // |
422 // |
397 // |
423 { |
398 { |
424 __KTRACE_OPT(KDMA, Kern::Printf(">DmaChannelMgr::Open aOpenId=%d", aOpenId)); |
399 __KTRACE_OPT(KDMA, Kern::Printf(">DmaChannelMgr::Open aOpenId=%d", aOpenId)); |