|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <concept id="GUID-535E5C2A-DCFD-4BCB-B26B-11E88BDB8A8A" xml:lang="en"><title>TDmac Derived Class Implementation</title><shortdesc>Implementing the hardware-specific DMA controller.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
13 <p>The <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> class is part of the PIL. It is a |
|
14 container for the DMA controller's channels, descriptors and descriptor |
|
15 headers. It also defines virtual functions for operations that require |
|
16 a PSL implementation.</p> |
|
17 <p>You need to derive <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> for each distinct type |
|
18 of DMA controller on your device, and implement these virtual functions.</p> |
|
19 <p><table id="GUID-2AB9BEBC-9C41-4CAC-A222-24083FAD5F2B"> |
|
20 <tgroup cols="3"><colspec colname="col1"/><colspec colname="COLSPEC1" colwidth="1.00*"/><colspec colname="col2"/> |
|
21 <thead> |
|
22 <row> |
|
23 <entry valign="top">Function</entry> |
|
24 <entry valign="top">Mandatory/Conditional</entry> |
|
25 <entry valign="top">Description</entry> |
|
26 </row> |
|
27 </thead> |
|
28 <tbody> |
|
29 <row> |
|
30 <entry><xref href="GUID-E0617B44-6C99-3327-9E20-2975E465AA8C.dita"><apiname>Transfer()</apiname></xref></entry> |
|
31 <entry>Mandatory</entry> |
|
32 <entry>For single buffer and scatter/gather, this starts the DMA transfer. |
|
33 For double buffer, this prepares the next fragment to transfer while |
|
34 a current transfer is in operation</entry> |
|
35 </row> |
|
36 <row> |
|
37 <entry><xref href="GUID-267716ED-F59A-35FB-89CC-FB82540FEA79.dita"><apiname>StopTransfer()</apiname></xref></entry> |
|
38 <entry>Mandatory</entry> |
|
39 <entry>Stop the specified channel synchronously. Must not return to |
|
40 the PSL implementation until the channel has stopped.</entry> |
|
41 </row> |
|
42 <row> |
|
43 <entry><xref href="GUID-ACF1D126-591B-3A84-9F53-94370B1BFA7B.dita"><apiname>IsIdle()</apiname></xref></entry> |
|
44 <entry>Mandatory</entry> |
|
45 <entry>Returns <codeph>ETrue</codeph> if specified channel is idle, |
|
46 otherwise <codeph>EFalse</codeph></entry> |
|
47 </row> |
|
48 <row> |
|
49 <entry><xref href="GUID-D8ECA8CE-7F7C-356D-9C9F-4BD37ED2618C.dita"><apiname>MaxTransferSize()</apiname></xref></entry> |
|
50 <entry>Optional</entry> |
|
51 <entry>Takes the parameters and evaluates the maximum transfer size |
|
52 in bytes.</entry> |
|
53 </row> |
|
54 <row> |
|
55 <entry><xref href="GUID-F6CBDDF7-A9C1-3534-9F5E-5B4FC77E888B.dita"><apiname>MemAlignMask()</apiname></xref></entry> |
|
56 <entry>Optional</entry> |
|
57 <entry><i>This applies to DMA v1 only.</i></entry> |
|
58 </row> |
|
59 <row> |
|
60 <entry><xref href="GUID-AA9217AF-EF1C-3010-AA7E-A4D3FCA14B30.dita"><apiname>InitHwDes()</apiname></xref></entry> |
|
61 <entry>Optional</entry> |
|
62 <entry>For scatter-gather, initialise the array of memory areas and |
|
63 set up the first block of data to be transferred.</entry> |
|
64 </row> |
|
65 <row> |
|
66 <entry><xref href="GUID-DCEFF8BA-BC74-3DA4-88CC-6A2C2E928BFE.dita"><apiname>ChainHwDes()</apiname></xref></entry> |
|
67 <entry>Optional</entry> |
|
68 <entry>For scatter-gather, add additional blocks of data to transfer |
|
69 to the list of memory areas.</entry> |
|
70 </row> |
|
71 <row> |
|
72 <entry><xref href="GUID-7076A78C-24F8-36B0-8FC2-F4DA8AB6DC14.dita"><apiname>AppendHwDes()</apiname></xref></entry> |
|
73 <entry>Optional</entry> |
|
74 <entry>For scatter-gather, add to the array of memory areas while |
|
75 the transfer is active. This is used in particular for streaming data |
|
76 where new descriptors can be added to the end of the chain while data |
|
77 earlier in the train is being transferred. E.g. video streaming.</entry> |
|
78 </row> |
|
79 <row> |
|
80 <entry><xref href="GUID-9D519453-8CA5-3200-8E9A-BB1599C25CE9.dita"><apiname>UnlinkHwDes()</apiname></xref></entry> |
|
81 <entry>Optional</entry> |
|
82 <entry>For scatter-gather, remove items from the array of memory areas.</entry> |
|
83 </row> |
|
84 <row> |
|
85 <entry><xref href="GUID-5569F5DA-D5FD-3368-99E4-F9AE6E1A7752.dita"><apiname>FailNext()</apiname></xref></entry> |
|
86 <entry>Optional</entry> |
|
87 <entry>For a sequence of memory transfers, tell the next one to fail. </entry> |
|
88 </row> |
|
89 <row> |
|
90 <entry><xref href="GUID-ED81D339-84D6-3811-AC39-184D6AC723C0.dita"><apiname>MissNextInterrupts()</apiname></xref></entry> |
|
91 <entry>Optional</entry> |
|
92 <entry>DMA transfers start on the next interrupt, but sometimes you |
|
93 want to skip the next interrupt for synchronisation or other reasons.</entry> |
|
94 </row> |
|
95 <row> |
|
96 <entry><xref href="GUID-93A3F01A-3489-37E5-921C-5EA5228545AA.dita"><apiname>Extension()</apiname></xref></entry> |
|
97 <entry>Optional</entry> |
|
98 <entry>Pass a command from the application/client down to the DMA |
|
99 chipset. Hardware dependent.</entry> |
|
100 </row> |
|
101 </tbody> |
|
102 </tgroup> |
|
103 </table></p> |
|
104 <section id="GUID-525949BF-21B1-40DA-888E-D05B204BC382"><title>Implement |
|
105 the mandatory controller virtual functions</title> <p>The <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> class contains several pure virtual functions that |
|
106 must be implemented by the PSL implementation: </p><ul> |
|
107 <li id="GUID-5FE89E59-2C8F-417E-AC84-77C8F20EA2E7"><xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-81921A9D-41F5-34BC-B882-60CC4CD807FB"><apiname>TDmac::Transfer()</apiname></xref></li> |
|
108 <li id="GUID-1D62C97A-5DC6-4BEE-B3EC-9120808FBFD6"><xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-B738D1B9-80FA-334D-ABEB-DFFF093E0B9D"><apiname>TDmac::StopTransfer()</apiname></xref></li> |
|
109 <li id="GUID-1708E632-4C79-4274-9363-4528095342A6"><xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-7422834D-CE6B-32DB-A040-7762A8BAB7D7"><apiname>TDmac::IsIdle()</apiname></xref></li> |
|
110 </ul> <p>These functions start and stop transfers on a DMA channel |
|
111 and are the main interface between the PIL and the PSL. The implementation |
|
112 of these functions depends on the hardware available for performing |
|
113 DMA, and on the characteristics used to specify a DMA transfer: </p><ul> |
|
114 <li id="GUID-93F00482-7DB7-4D0B-9BBC-62D0DEDFC669">the source and |
|
115 destination addresses </li> |
|
116 <li id="GUID-2BF651D7-261B-4B70-A281-07C14C0837D0">the burst size </li> |
|
117 <li id="GUID-638B0F70-6595-4B8C-8B46-22023B5AAF12">the maximum transfer |
|
118 size </li> |
|
119 <li id="GUID-879FE6AA-0D3E-4BAD-AB32-C3F6B4CB6758">the transfer width, |
|
120 i.e. number of bits per memory access </li> |
|
121 <li id="GUID-FD9A86D2-2BE6-4600-B0EF-54CCC2854D5D">the memory alignment |
|
122 and endianness. </li> |
|
123 </ul> <p>The DMA Framework manages the transfer descriptors according |
|
124 to the descriptor parameter passed into the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> constructor by the derived class constructor; the descriptor parameter |
|
125 is a <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-BBD2153C-4B41-357C-9299-D710930AFCBE"><apiname>TDmac::SCreateInfo</apiname></xref> structure. The per-request |
|
126 transfer parameters are passed into the descriptors for each request |
|
127 issued by a driver. </p></section> |
|
128 <section id="GUID-9D4B491F-2E42-407F-BC99-E1F32AE6549E"><title>The |
|
129 transfer function: Transfer()</title> <p>This function initiates a |
|
130 previously constructed request on a specific channel. This is the |
|
131 template implementation: </p> <codeblock xml:space="preserve"> |
|
132 void TTemplateDmac::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) |
|
133 // |
|
134 // Initiates a (previously constructed) request on a specific channel. |
|
135 // |
|
136 { |
|
137 const TUint8 i = static_cast&<TUint8&>(aChannel.PslId()); |
|
138 TDmaDesc* pD = HdrToHwDes(aHdr); |
|
139 |
|
140 __KTRACE_OPT(KDMA, Kern::Printf("&>TTemplateDmac::Transfer channel=%d des=0x%08X", i, pD)); |
|
141 |
|
142 // Load the first descriptor address into the DMAC and start it |
|
143 // by setting the RUN bit. |
|
144 (void) *pD, (void) i; |
|
145 |
|
146 } |
|
147 </codeblock> </section> |
|
148 <section id="GUID-56D77E64-1AD3-4F17-AD26-562AEB97DC56"><title>The |
|
149 stop transfer function: StopTransfer()</title> <p>This is the template |
|
150 implementation: </p> <codeblock xml:space="preserve">void TTemplateDmac::StopTransfer(const TDmaChannel& aChannel) |
|
151 // |
|
152 // Stops a running channel. |
|
153 // |
|
154 { |
|
155 const TUint8 i = static_cast&<TUint8&>(aChannel.PslId()); |
|
156 |
|
157 __KTRACE_OPT(KDMA, Kern::Printf("&>TTemplateDmac::StopTransfer channel=%d", i)); |
|
158 |
|
159 } |
|
160 </codeblock></section> |
|
161 <section id="GUID-C2427406-8F3A-407D-8D3D-9B3040542054"><title>The |
|
162 function: IsIdle()</title> <p><xref href="GUID-ACF1D126-591B-3A84-9F53-94370B1BFA7B.dita"><apiname>IsIdle()</apiname></xref> returns |
|
163 the state of a given channel. This is the template implementation: </p> <codeblock xml:space="preserve">TBool TTemplateDmac::IsIdle(const TDmaChannel& aChannel) |
|
164 // |
|
165 // Returns the state of a given channel. |
|
166 // |
|
167 { |
|
168 const TUint8 i = static_cast&<TUint8&>(aChannel.PslId()); |
|
169 |
|
170 __KTRACE_OPT(KDMA, Kern::Printf("&>TTemplateDmac::IsIdle channel=%d", i)); |
|
171 |
|
172 return ETrue; |
|
173 } |
|
174 </codeblock> </section> |
|
175 <section id="GUID-A385DE6A-E267-4F0C-A0AC-A85316706D68"><title>Implement |
|
176 the non-mandatory controller virtual functions</title> <p>The following |
|
177 auxiliary functions are used to implement the scatter-gather transfer |
|
178 mode behavior by creating and manipulating the linked list of transfer |
|
179 fragment headers that describe a given scatter-gather transaction. |
|
180 They are called by the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> base class functions |
|
181 when the instance of the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> derived class reports |
|
182 itself as being capable of scatter-gather operations. </p> <ul> |
|
183 <li id="GUID-8CFB839A-A2A2-47C5-A75A-062CE205FB0A"><xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-90AC3E58-E589-3F91-85F7-16A4ADFFFA69"><apiname>TDmac::InitHwDes()</apiname></xref></li> |
|
184 <li id="GUID-58BDB319-0A8D-4C1B-8C75-6C9E119D26DF"><xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-05021B05-75DE-3F75-92C6-8B9445EB86D3"><apiname>TDmac::ChainHwDes()</apiname></xref></li> |
|
185 <li id="GUID-2998E58B-2A02-4A66-87F5-A87F1915F47C"><xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-AFCDDA16-991D-3BDA-B90B-87BCAFF66E5C"><apiname>TDmac::AppendHwDes()</apiname></xref></li> |
|
186 </ul></section> |
|
187 <section id="GUID-4B1544BB-A3BC-4938-8832-FCD86C647953"><title>First |
|
188 scatter-gather support function: InitHwDes()</title> <p>This is a |
|
189 function for creating a scatter-gather list. From the information |
|
190 in the passed-in request, the function sets up the descriptor with |
|
191 that fragment's: </p><ul> |
|
192 <li id="GUID-A585C7E8-0C14-4F62-BB6B-C34FB4DEC0D1">source and destination |
|
193 address </li> |
|
194 <li id="GUID-5A58FD8F-BC32-48B9-BFA3-B376E4BD2ACC">size </li> |
|
195 <li id="GUID-C5BC6402-011F-497A-B3C2-C3AB5F29E1C7">driver/DMA controller |
|
196 specific transfer parameters: memory/peripheral, burst size, transfer |
|
197 width. </li> |
|
198 </ul> <p>This is the template implementation: </p> <codeblock xml:space="preserve">void TTemplateDmac::InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, |
|
199 TUint aFlags, TUint32 aPslInfo, TUint32 /*aCookie*/) |
|
200 // |
|
201 // Sets up (from a passed in request) the descriptor with that fragment's source and destination address, |
|
202 // the fragment size, and the (driver/DMA controller) specific transfer parameters (mem/peripheral, |
|
203 // burst size, transfer width). |
|
204 // |
|
205 { |
|
206 TDmaDesc* pD = HdrToHwDes(aHdr); |
|
207 |
|
208 __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD)); |
|
209 |
|
210 // Unaligned descriptor? Error in generic layer! |
|
211 __DMA_ASSERTD(IsHwDesAligned(pD)); |
|
212 |
|
213 pD-&>iSrcAddr = (aFlags & KDmaPhysAddrSrc) ? aSrc : Epoc::LinearToPhysical(aSrc); |
|
214 pD-&>iDestAddr = (aFlags & KDmaPhysAddrDest) ? aDest : Epoc::LinearToPhysical(aDest); |
|
215 pD-&>iCmd = DcmdReg(aCount, aFlags, aPslInfo); |
|
216 pD-&>iDescAddr = TDmaDesc::KStopBitMask; |
|
217 } |
|
218 </codeblock> </section> |
|
219 <section id="GUID-FAAE402C-959D-40CD-B208-C5AB9E495CAB"><title>Second |
|
220 scatter-gather support function: ChainHwDes()</title> <p>If the framework |
|
221 needs to fragment the client’s request, either because of the transfer |
|
222 size or because the memory is not a single contiguous block, then |
|
223 the framework calls this function. It chains hardware descriptors |
|
224 together by setting the next pointer of the original descriptor to |
|
225 the physical address of the descriptor to be chained. It assumes that |
|
226 the DMAC channel is quiescent when called. </p> <p>This is the template |
|
227 implementation: </p> <codeblock xml:space="preserve">void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr) |
|
228 // |
|
229 // Chains hardware descriptors together by setting the next pointer of the original descriptor |
|
230 // to the physical address of the descriptor to be chained. |
|
231 // |
|
232 { |
|
233 TDmaDesc* pD = HdrToHwDes(aHdr); |
|
234 TDmaDesc* pN = HdrToHwDes(aNextHdr); |
|
235 |
|
236 __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::ChainHwDes des=0x%08X next des=0x%08X", pD, pN)); |
|
237 |
|
238 // Unaligned descriptor? Error in generic layer! |
|
239 __DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN)); |
|
240 |
|
241 pD-&>iDescAddr = DesLinToPhys(pN); |
|
242 } |
|
243 </codeblock></section> |
|
244 <section id="GUID-60013038-5A06-4926-A7F4-68D6FBA79ABC"><title>Third |
|
245 scatter-gather support function: AppendHwDes() </title> <p>This function |
|
246 is called by the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> base class when a driver |
|
247 request is called for a channel that is still active, i.e. where the |
|
248 intent is to provide data streaming so that the target device is constantly |
|
249 provided with data; for example, an audio device playing a track. |
|
250 In this case, the function provided by the derived class must: </p> <ul> |
|
251 <li id="GUID-484E794E-A446-4AFD-8956-D072C6B5EC81">stop the DMAC to |
|
252 prevent any corruption of the scatter-gather list while appending |
|
253 the new fragment descriptor </li> |
|
254 <li id="GUID-2D05CB0A-450A-45DF-8736-E406CFC1C6A2">append the new |
|
255 descriptor </li> |
|
256 <li id="GUID-E638DFC8-8078-4D5A-AC78-1A06B01DDBE5">re-enable the channel, |
|
257 ideally before the target has detected the gap in service. </li> |
|
258 </ul> <p>This is the template implementation: </p> <codeblock xml:space="preserve">void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, |
|
259 const SDmaDesHdr& aNewHdr) |
|
260 // |
|
261 // Appends a descriptor to the chain while the channel is running. |
|
262 // |
|
263 { |
|
264 const TUint8 i = static_cast&<TUint8&>(aChannel.PslId()); |
|
265 |
|
266 TDmaDesc* pL = HdrToHwDes(aLastHdr); |
|
267 TDmaDesc* pN = HdrToHwDes(aNewHdr); |
|
268 |
|
269 __KTRACE_OPT(KDMA, Kern::Printf("&>TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X", |
|
270 i, pL, pN)); |
|
271 // Unaligned descriptor? Error in generic layer! |
|
272 __DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN)); |
|
273 |
|
274 TPhysAddr newPhys = DesLinToPhys(pN); |
|
275 |
|
276 const TInt irq = NKern::DisableAllInterrupts(); |
|
277 StopTransfer(aChannel); |
|
278 |
|
279 pL-&>iDescAddr = newPhys; |
|
280 const TTemplateSgChannel& channel = static_cast&<const TTemplateSgChannel&&>(aChannel); |
|
281 TDmaDesc* pD = channel.iTmpDes; |
|
282 |
|
283 (void) *pD, (void) i; |
|
284 |
|
285 NKern::RestoreInterrupts(irq); |
|
286 |
|
287 __KTRACE_OPT(KDMA, Kern::Printf("&<TTemplateDmac::AppendHwDes")); |
|
288 } |
|
289 </codeblock></section> |
|
290 </conbody><related-links> |
|
291 <link href="GUID-4E3C086B-25BE-4DAC-9E21-CFC4F8B792A5.dita"><linktext>DMA |
|
292 Technology Guide</linktext></link> |
|
293 <link href="GUID-95A33491-17AC-4F12-948E-A1352ADDA483.dita"><linktext>DMA |
|
294 Implementation Guide</linktext></link> |
|
295 </related-links></concept> |