OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
HdaControllerMem.c
Go to the documentation of this file.
1/*
2 * File: HdaControllerMem.c
3 *
4 * Copyright (c) 2018, 2020 John Davis
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include "HdaController.h"
27#include <Library/OcMiscLib.h>
29
30EFI_STATUS
32 IN HDA_RING_BUFFER *HdaRingBuffer,
33 IN HDA_CONTROLLER_DEV *HdaDev,
35 )
36{
37 EFI_STATUS Status;
38 EFI_PCI_IO_PROTOCOL *PciIo;
39 UINT32 Offset;
40 UINT32 EntrySize;
41
42 UINT8 HdaRingSize;
43 UINT32 HdaRingLowerBaseAddr;
44 UINT32 HdaRingUpperBaseAddr;
45
46 UINTN BufferSizeActual;
47
48 UINT16 RintCnt;
49
50 ASSERT (HdaRingBuffer != NULL);
51 ASSERT (HdaDev != NULL);
52
53 if (Type == HDA_RING_BUFFER_TYPE_CORB) {
54 Offset = HDA_REG_CORB_BASE;
55 EntrySize = HDA_CORB_ENTRY_SIZE;
56 } else if (Type == HDA_RING_BUFFER_TYPE_RIRB) {
57 Offset = HDA_REG_RIRB_BASE;
58 EntrySize = HDA_RIRB_ENTRY_SIZE;
59 } else {
60 return EFI_INVALID_PARAMETER;
61 }
62
63 HdaRingBuffer->HdaDev = HdaDev;
64 HdaRingBuffer->Type = Type;
65 PciIo = HdaDev->PciIo;
66
67 //
68 // Get current value of size register.
69 //
70 Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, Offset + HDA_OFFSET_RING_SIZE, 1, &HdaRingSize);
71 if (EFI_ERROR (Status)) {
72 return Status;
73 }
74
75 //
76 // Calculate size of ring buffer based on supported sizes.
77 //
78 if (HdaRingSize & HDA_OFFSET_RING_SIZE_SZCAP_256) {
79 HdaRingBuffer->BufferSize = 256 * EntrySize;
80 HdaRingSize = (HdaRingSize & ~HDA_OFFSET_RING_SIZE_MASK) | HDA_OFFSET_RING_SIZE_ENT256;
81 } else if (HdaRingSize & HDA_OFFSET_RING_SIZE_SZCAP_16) {
82 HdaRingBuffer->BufferSize = 16 * EntrySize;
83 HdaRingSize = (HdaRingSize & ~HDA_OFFSET_RING_SIZE_MASK) | HDA_OFFSET_RING_SIZE_ENT16;
84 } else if (HdaRingSize & HDA_OFFSET_RING_SIZE_SZCAP_2) {
85 HdaRingBuffer->BufferSize = 2 * EntrySize;
86 HdaRingSize = (HdaRingSize & ~HDA_OFFSET_RING_SIZE_MASK) | HDA_OFFSET_RING_SIZE_ENT2;
87 } else {
88 //
89 // Unsupported size.
90 //
91 return EFI_UNSUPPORTED;
92 }
93
94 HdaRingBuffer->Buffer = NULL;
95 HdaRingBuffer->Mapping = NULL;
96
97 //
98 // Allocate buffer.
99 //
100 Status = PciIo->AllocateBuffer (
101 PciIo,
102 AllocateAnyPages,
103 EfiBootServicesData,
104 EFI_SIZE_TO_PAGES (HdaRingBuffer->BufferSize),
105 &HdaRingBuffer->Buffer,
106 0
107 );
108 if (EFI_ERROR (Status)) {
109 return Status;
110 }
111
112 ZeroMem (HdaRingBuffer->Buffer, HdaRingBuffer->BufferSize);
113
114 //
115 // Map buffer.
116 //
117 BufferSizeActual = HdaRingBuffer->BufferSize;
118 Status = PciIo->Map (
119 PciIo,
120 EfiPciIoOperationBusMasterCommonBuffer,
121 HdaRingBuffer->Buffer,
122 &BufferSizeActual,
123 &HdaRingBuffer->PhysAddr,
124 &HdaRingBuffer->Mapping
125 );
126 if (EFI_ERROR (Status)) {
127 return Status;
128 }
129
130 if (BufferSizeActual != HdaRingBuffer->BufferSize) {
131 return EFI_NO_MAPPING;
132 }
133
134 //
135 // Ensure ring buffer is stopped.
136 //
137 Status = HdaControllerSetRingBufferState (HdaRingBuffer, FALSE, Type);
138 if (EFI_ERROR (Status)) {
139 return Status;
140 }
141
142 //
143 // Set buffer lower base address.
144 //
145 HdaRingLowerBaseAddr = (UINT32)HdaRingBuffer->PhysAddr;
146 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, PCI_HDA_BAR, Offset + HDA_OFFSET_RING_BASE, 1, &HdaRingLowerBaseAddr);
147 if (EFI_ERROR (Status)) {
148 return Status;
149 }
150
151 //
152 // If 64-bit buffers are supported, also set upper base address.
153 //
154 if (HdaRingBuffer->HdaDev->Capabilities & HDA_REG_GCAP_64OK) {
155 HdaRingUpperBaseAddr = (UINT32)(HdaRingBuffer->PhysAddr >> 32);
156 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, PCI_HDA_BAR, Offset + HDA_OFFSET_RING_UBASE, 1, &HdaRingUpperBaseAddr);
157 if (EFI_ERROR (Status)) {
158 return Status;
159 }
160 }
161
162 //
163 // Reset ring buffer.
164 //
165 Status = HdaControllerResetRingBuffer (HdaRingBuffer);
166 if (EFI_ERROR (Status)) {
167 DEBUG ((
168 DEBUG_WARN,
169 "HDA: Reset %a - %r\n",
170 HdaRingBuffer->Type == HDA_RING_BUFFER_TYPE_CORB ? "CORB" : "RIRB",
171 Status
172 ));
173 return Status;
174 }
175
176 if (HdaRingBuffer->HdaDev->Quirks & HDA_CONTROLLER_QUIRK_QEMU_1) {
177 RintCnt = 0x1;
178 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint16, PCI_HDA_BAR, HDA_REG_RINTCNT, 1, &RintCnt);
179 if (EFI_ERROR (Status)) {
180 return Status;
181 }
182 }
183
184 HdaRingBuffer->EntryCount = (UINT32)(HdaRingBuffer->BufferSize / EntrySize);
185 DEBUG ((
186 DEBUG_VERBOSE,
187 "HDA controller ring buffer allocated @ 0x%p (0x%p) (%u entries)\n",
188 HdaRingBuffer->Buffer,
189 HdaRingBuffer->PhysAddr,
190 HdaRingBuffer->EntryCount
191 ));
192
193 return EFI_SUCCESS;
194}
195
196VOID
198 IN HDA_RING_BUFFER *HdaRingBuffer,
200 )
201{
202 EFI_PCI_IO_PROTOCOL *PciIo;
203
204 ASSERT (HdaRingBuffer != NULL);
205
206 //
207 // Already freed if NULL.
208 //
209 if (HdaRingBuffer->HdaDev == NULL) {
210 return;
211 }
212
213 PciIo = HdaRingBuffer->HdaDev->PciIo;
214
215 //
216 // Unmap and free ring buffer.
217 //
218 HdaControllerSetRingBufferState (HdaRingBuffer, FALSE, Type);
219 if (HdaRingBuffer->Mapping != NULL) {
220 PciIo->Unmap (PciIo, HdaRingBuffer->Mapping);
221 }
222
223 if (HdaRingBuffer->Buffer != NULL) {
224 PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (HdaRingBuffer->BufferSize), HdaRingBuffer->Buffer);
225 }
226
227 HdaRingBuffer->Buffer = NULL;
228 HdaRingBuffer->BufferSize = 0;
229 HdaRingBuffer->EntryCount = 0;
230 HdaRingBuffer->Mapping = NULL;
231 HdaRingBuffer->PhysAddr = 0;
232 HdaRingBuffer->Pointer = 0;
233 HdaRingBuffer->HdaDev = NULL;
234}
235
236EFI_STATUS
238 IN HDA_RING_BUFFER *HdaRingBuffer,
239 IN BOOLEAN Enable,
241 )
242{
243 EFI_STATUS Status;
244 EFI_PCI_IO_PROTOCOL *PciIo;
245 UINT32 Offset;
246 UINT8 CtlFlags;
247 UINT8 HdaRingCtl;
248 UINT64 Tmp;
249
250 PciIo = HdaRingBuffer->HdaDev->PciIo;
251
252 if (HdaRingBuffer->Type == HDA_RING_BUFFER_TYPE_CORB) {
253 Offset = HDA_REG_CORB_BASE;
254 } else if (HdaRingBuffer->Type == HDA_RING_BUFFER_TYPE_RIRB) {
255 Offset = HDA_REG_RIRB_BASE;
256 } else {
257 return EFI_INVALID_PARAMETER;
258 }
259
260 //
261 // Get current value of CTL register.
262 //
263 Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, Offset + HDA_OFFSET_RING_CTL, 1, &HdaRingCtl);
264 if (EFI_ERROR (Status)) {
265 return Status;
266 }
267
268 CtlFlags = HDA_OFFSET_RING_CTL_RUN;
269 if (HdaRingBuffer->HdaDev->Quirks & HDA_CONTROLLER_QUIRK_QEMU_1) {
270 CtlFlags |= HDA_REG_RIRBCTL_RINTCTL;
271 }
272
273 if (Enable) {
274 HdaRingCtl |= CtlFlags;
275 } else {
276 HdaRingCtl &= ~CtlFlags;
277 }
278
279 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, Offset + HDA_OFFSET_RING_CTL, 1, &HdaRingCtl);
280 if (EFI_ERROR (Status)) {
281 return Status;
282 }
283
284 //
285 // Wait for bit to cycle indicating the ring buffer has stopped/started.
286 //
287 Status = PciIo->PollMem (
288 PciIo,
289 EfiPciIoWidthUint8,
291 Offset + HDA_OFFSET_RING_CTL,
293 Enable ? HDA_OFFSET_RING_CTL_RUN : 0,
295 &Tmp
296 );
297 if (EFI_ERROR (Status)) {
298 return Status;
299 }
300
301 return EFI_SUCCESS;
302}
303
304EFI_STATUS
306 IN HDA_RING_BUFFER *HdaRingBuffer
307 )
308{
309 EFI_STATUS Status;
310 EFI_PCI_IO_PROTOCOL *PciIo;
311 UINT16 HdaRingPointer;
312 UINT64 HdaRingPointerPollResult;
313
314 PciIo = HdaRingBuffer->HdaDev->PciIo;
315
316 //
317 // Reset read/write pointers.
318 //
319 if (HdaRingBuffer->Type == HDA_RING_BUFFER_TYPE_CORB) {
320 //
321 // Clear write pointer.
322 //
323 HdaRingPointer = 0;
324 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint16, PCI_HDA_BAR, HDA_REG_CORBWP, 1, &HdaRingPointer);
325 if (EFI_ERROR (Status)) {
326 return Status;
327 }
328
329 //
330 // Set reset bit in read pointer register, and per spec wait for bit to set.
331 //
332 HdaRingPointer = HDA_REG_CORBRP_RST;
333 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint16, PCI_HDA_BAR, HDA_REG_CORBRP, 1, &HdaRingPointer);
334 if (EFI_ERROR (Status)) {
335 return Status;
336 }
337
338 if (!(HdaRingBuffer->HdaDev->Quirks & HDA_CONTROLLER_QUIRK_CORB_NO_POLL_RESET)) {
339 Status = PciIo->PollMem (PciIo, EfiPciIoWidthUint16, PCI_HDA_BAR, HDA_REG_CORBRP, HDA_REG_CORBRP_RST, HDA_REG_CORBRP_RST, MS_TO_NANOSECONDS (50), &HdaRingPointerPollResult);
340 if (EFI_ERROR (Status)) {
341 return Status;
342 }
343 }
344
345 //
346 // Per spec, clear bit and wait for bit to clear.
347 //
348 HdaRingPointer = 0;
349 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint16, PCI_HDA_BAR, HDA_REG_CORBRP, 1, &HdaRingPointer);
350 if (EFI_ERROR (Status)) {
351 return Status;
352 }
353
354 Status = PciIo->PollMem (PciIo, EfiPciIoWidthUint16, PCI_HDA_BAR, HDA_REG_CORBRP, HDA_REG_CORBRP_RST, 0, MS_TO_NANOSECONDS (50), &HdaRingPointerPollResult);
355 if (EFI_ERROR (Status)) {
356 return Status;
357 }
358 } else if (HdaRingBuffer->Type == HDA_RING_BUFFER_TYPE_RIRB) {
359 //
360 // RIRB requires only the reset bit be set.
361 //
362 Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint16, PCI_HDA_BAR, HDA_REG_RIRBWP, 1, &HdaRingPointer);
363 if (EFI_ERROR (Status)) {
364 return Status;
365 }
366
367 HdaRingPointer |= HDA_REG_RIRBWP_RST;
368 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint16, PCI_HDA_BAR, HDA_REG_RIRBWP, 1, &HdaRingPointer);
369 if (EFI_ERROR (Status)) {
370 return Status;
371 }
372 } else {
373 return EFI_INVALID_PARAMETER;
374 }
375
376 return EFI_SUCCESS;
377}
378
379EFI_STATUS
381 IN HDA_CONTROLLER_DEV *HdaDev
382 )
383{
384 EFI_STATUS Status;
385 EFI_PCI_IO_PROTOCOL *PciIo;
386 UINT32 LowerBaseAddr;
387 UINT32 UpperBaseAddr;
388 EFI_PHYSICAL_ADDRESS DataBlockAddr;
389 HDA_STREAM *HdaStream;
390
391 UINT8 InputStreamsCount;
392 UINT8 OutputStreamsCount;
393 UINT8 BidirStreamsCount;
394 UINT32 TotalStreamsCount;
395 UINT32 OutputStreamsOffset;
396 UINT32 BidirStreamsOffset;
397
398 UINT32 Index;
399 UINT32 Index2;
400 UINTN PciLengthActual;
401
402 ASSERT (HdaDev != NULL);
403
404 PciIo = HdaDev->PciIo;
405
406 //
407 // Reset stream ID bitmap so stream 0 is allocated (reserved).
408 //
409 HdaDev->StreamIdMapping = BIT0;
410
411 InputStreamsCount = HDA_REG_GCAP_ISS (HdaDev->Capabilities);
412 OutputStreamsCount = HDA_REG_GCAP_OSS (HdaDev->Capabilities);
413 BidirStreamsCount = HDA_REG_GCAP_BSS (HdaDev->Capabilities);
414 TotalStreamsCount = InputStreamsCount + OutputStreamsCount + BidirStreamsCount;
415 OutputStreamsOffset = InputStreamsCount;
416 BidirStreamsOffset = OutputStreamsOffset + OutputStreamsCount;
417
418 HdaDev->StreamsCount = OutputStreamsCount + BidirStreamsCount;
419 HdaDev->Streams = AllocateZeroPool (sizeof (HDA_STREAM) * HdaDev->StreamsCount);
420 if (HdaDev->Streams == NULL) {
421 return EFI_OUT_OF_RESOURCES;
422 }
423
424 DEBUG ((DEBUG_VERBOSE, "AudioDxe: Total output-capable streams: %u\n", HdaDev->StreamsCount));
425
426 for (Index = 0; Index < HdaDev->StreamsCount; Index++) {
427 HdaStream = &HdaDev->Streams[Index];
428 HdaStream->HdaDev = HdaDev;
429 HdaStream->Index = (UINT8)(Index + OutputStreamsOffset);
430 HdaStream->IsBidirectional = Index + OutputStreamsOffset >= BidirStreamsOffset;
431
432 //
433 // Set this once Index is valid and before doing anything which requires cleanup.
434 //
435 HdaStream->HasIndex = TRUE;
436
437 //
438 // Initialize polling timer.
439 //
440 Status = gBS->CreateEvent (
441 EVT_TIMER | EVT_NOTIFY_SIGNAL,
442 TPL_NOTIFY,
444 HdaStream,
445 &HdaStream->PollTimer
446 );
447 if (EFI_ERROR (Status)) {
448 HdaStream->PollTimer = NULL;
449 return Status;
450 }
451
452 //
453 // Allocate buffer descriptor list.
454 //
455 Status = PciIo->AllocateBuffer (
456 PciIo,
457 AllocateAnyPages,
458 EfiBootServicesData,
459 EFI_SIZE_TO_PAGES (HDA_BDL_SIZE),
460 (VOID **)&HdaStream->BufferList,
461 0
462 );
463 if (EFI_ERROR (Status)) {
464 return Status;
465 }
466
467 ZeroMem (HdaStream->BufferList, HDA_BDL_SIZE);
468
469 //
470 // Map buffer descriptor list.
471 //
472 PciLengthActual = HDA_BDL_SIZE;
473 Status = PciIo->Map (
474 PciIo,
475 EfiPciIoOperationBusMasterCommonBuffer,
476 HdaStream->BufferList,
477 &PciLengthActual,
478 &HdaStream->BufferListPhysAddr,
479 &HdaStream->BufferListMapping
480 );
481 if (EFI_ERROR (Status) || (PciLengthActual != HDA_BDL_SIZE)) {
482 return Status;
483 }
484
485 if (!HdaControllerResetStream (HdaStream)) {
486 return EFI_UNSUPPORTED;
487 }
488
489 //
490 // Allocate buffer for data.
491 //
492 Status = PciIo->AllocateBuffer (
493 PciIo,
494 AllocateAnyPages,
495 EfiBootServicesData,
496 EFI_SIZE_TO_PAGES (HDA_STREAM_BUF_SIZE),
497 (VOID **)&HdaStream->BufferData,
498 0
499 );
500 if (EFI_ERROR (Status)) {
501 return Status;
502 }
503
505
506 //
507 // Map buffer descriptor list.
508 //
509 PciLengthActual = HDA_STREAM_BUF_SIZE;
510 Status = PciIo->Map (
511 PciIo,
512 EfiPciIoOperationBusMasterCommonBuffer,
513 HdaStream->BufferData,
514 &PciLengthActual,
515 &HdaStream->BufferDataPhysAddr,
516 &HdaStream->BufferDataMapping
517 );
518 if (EFI_ERROR (Status) || (PciLengthActual != HDA_STREAM_BUF_SIZE)) {
519 return Status;
520 }
521
522 //
523 // Fill buffer list.
524 //
525 for (Index2 = 0; Index2 < HDA_BDL_ENTRY_COUNT; Index2++) {
526 DataBlockAddr = HdaStream->BufferDataPhysAddr + (Index2 * HDA_BDL_BLOCKSIZE);
527 HdaStream->BufferList[Index2].Address = (UINT32)DataBlockAddr;
528 HdaStream->BufferList[Index2].AddressHigh = (UINT32)(DataBlockAddr >> 32);
529 HdaStream->BufferList[Index2].Length = HDA_BDL_BLOCKSIZE;
530 HdaStream->BufferList[Index2].InterruptOnCompletion = TRUE;
531 }
532 }
533
534 //
535 // Allocate DMA positions structure.
536 //
537 HdaDev->DmaPositionsSize = sizeof (HDA_DMA_POS_ENTRY) * TotalStreamsCount;
538 Status = PciIo->AllocateBuffer (
539 PciIo,
540 AllocateAnyPages,
541 EfiBootServicesData,
542 EFI_SIZE_TO_PAGES (HdaDev->DmaPositionsSize),
543 (VOID **)&HdaDev->DmaPositions,
544 0
545 );
546 if (EFI_ERROR (Status)) {
547 return Status;
548 }
549
550 ZeroMem (HdaDev->DmaPositions, HdaDev->DmaPositionsSize);
551
552 // Map buffer descriptor list.
553 PciLengthActual = HdaDev->DmaPositionsSize;
554 Status = PciIo->Map (
555 PciIo,
556 EfiPciIoOperationBusMasterCommonBuffer,
557 HdaDev->DmaPositions,
558 &PciLengthActual,
559 &HdaDev->DmaPositionsPhysAddr,
560 &HdaDev->DmaPositionsMapping
561 );
562 if (EFI_ERROR (Status) || (PciLengthActual != HdaDev->DmaPositionsSize)) {
563 return Status;
564 }
565
566 //
567 // Set DMA positions lower base address.
568 //
569 LowerBaseAddr = ((UINT32)HdaDev->DmaPositionsPhysAddr) | HDA_REG_DPLBASE_EN;
570 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, PCI_HDA_BAR, HDA_REG_DPLBASE, 1, &LowerBaseAddr);
571 if (EFI_ERROR (Status)) {
572 return Status;
573 }
574
575 //
576 // If 64-bit supported, set DMA positions upper base address.
577 //
578 if (HdaDev->Capabilities & HDA_REG_GCAP_64OK) {
579 UpperBaseAddr = (UINT32)(HdaDev->DmaPositionsPhysAddr >> 32);
580 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, PCI_HDA_BAR, HDA_REG_DPUBASE, 1, &UpperBaseAddr);
581 if (EFI_ERROR (Status)) {
582 return Status;
583 }
584 }
585
586 return EFI_SUCCESS;
587}
588
589BOOLEAN
591 IN HDA_STREAM *HdaStream
592 )
593{
594 EFI_STATUS Status;
595 EFI_PCI_IO_PROTOCOL *PciIo;
596 UINT32 LowerBaseAddr;
597 UINT32 UpperBaseAddr;
598
599 UINT8 HdaStreamCtl1;
600 UINT8 HdaStreamCtl3;
601 UINT16 StreamLvi;
602 UINT32 StreamCbl;
603 UINT64 Tmp;
604
605 ASSERT (HdaStream != NULL);
606
607 PciIo = HdaStream->HdaDev->PciIo;
608
609 //
610 // Get value of control register.
611 //
612 Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, HDA_REG_SDNCTL1 (HdaStream->Index), 1, &HdaStreamCtl1);
613 if (EFI_ERROR (Status)) {
614 return FALSE;
615 }
616
617 //
618 // Set and wait for reset bit to be set.
619 //
620 HdaStreamCtl1 |= HDA_REG_SDNCTL1_SRST;
621 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, HDA_REG_SDNCTL1 (HdaStream->Index), 1, &HdaStreamCtl1);
622 if (EFI_ERROR (Status)) {
623 return FALSE;
624 }
625
626 if (!(HdaStream->HdaDev->Quirks & HDA_CONTROLLER_QUIRK_QEMU_2)) {
627 Status = PciIo->PollMem (
628 PciIo,
629 EfiPciIoWidthUint8,
631 HDA_REG_SDNCTL1 (HdaStream->Index),
634 MS_TO_NANOSECONDS (100),
635 &Tmp
636 );
637 if (EFI_ERROR (Status)) {
638 return FALSE;
639 }
640 }
641
642 Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, HDA_REG_SDNCTL1 (HdaStream->Index), 1, &HdaStreamCtl1);
643 if (EFI_ERROR (Status)) {
644 return FALSE;
645 }
646
647 //
648 // Docs state we need to clear the bit and wait for it to clear.
649 //
650 HdaStreamCtl1 &= ~HDA_REG_SDNCTL1_SRST;
651 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, HDA_REG_SDNCTL1 (HdaStream->Index), 1, &HdaStreamCtl1);
652 if (EFI_ERROR (Status)) {
653 return FALSE;
654 }
655
656 Status = PciIo->PollMem (
657 PciIo,
658 EfiPciIoWidthUint8,
660 HDA_REG_SDNCTL1 (HdaStream->Index),
662 0,
663 MS_TO_NANOSECONDS (100),
664 &Tmp
665 );
666 if (EFI_ERROR (Status)) {
667 return FALSE;
668 }
669
670 //
671 // If bidirectional stream, configure for output.
672 // This bit should be set immediately after reset.
673 //
674 if (HdaStream->IsBidirectional) {
675 //
676 // Get current value of stream control register.
677 //
678 Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, HDA_REG_SDNCTL3 (HdaStream->Index), 1, &HdaStreamCtl3);
679 if (EFI_ERROR (Status)) {
680 return FALSE;
681 }
682
683 //
684 // Set DIR bit and write stream control register.
685 //
686 HdaStreamCtl3 |= HDA_REG_SDNCTL3_DIR;
687 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, HDA_REG_SDNCTL3 (HdaStream->Index), 1, &HdaStreamCtl3);
688 if (EFI_ERROR (Status)) {
689 return FALSE;
690 }
691 }
692
693 //
694 // Set BDL lower base address.
695 //
696 LowerBaseAddr = (UINT32)HdaStream->BufferListPhysAddr;
697 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, PCI_HDA_BAR, HDA_REG_SDNBDPL (HdaStream->Index), 1, &LowerBaseAddr);
698 if (EFI_ERROR (Status)) {
699 return FALSE;
700 }
701
702 //
703 // If 64-bit supported, set BDL upper base address.
704 //
705 if (HdaStream->HdaDev->Capabilities & HDA_REG_GCAP_64OK) {
706 UpperBaseAddr = (UINT32)(HdaStream->BufferListPhysAddr >> 32);
707 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, PCI_HDA_BAR, HDA_REG_SDNBDPU (HdaStream->Index), 1, &UpperBaseAddr);
708 if (EFI_ERROR (Status)) {
709 return FALSE;
710 }
711 }
712
713 //
714 // Set last valid index (LVI) and total buffer length.
715 //
716 StreamLvi = HDA_BDL_ENTRY_LAST;
717 StreamCbl = HDA_STREAM_BUF_SIZE;
718 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint16, PCI_HDA_BAR, HDA_REG_SDNLVI (HdaStream->Index), 1, &StreamLvi);
719 if (EFI_ERROR (Status)) {
720 return FALSE;
721 }
722
723 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, PCI_HDA_BAR, HDA_REG_SDNCBL (HdaStream->Index), 1, &StreamCbl);
724 if (EFI_ERROR (Status)) {
725 return FALSE;
726 }
727
728 HdaStream->DmaPositionTotal = 0;
729 HdaStream->DmaPositionLast = 0;
730 HdaStream->DmaPositionChangedMax = 0;
731 HdaStream->UseLpib = FALSE; // TODO: Allow being forced by NVRAM variable?
732 HdaStream->DmaCheckCount = 0;
733 HdaStream->DmaCheckComplete = FALSE;
734
735 return TRUE;
736}
737
738VOID
740 IN HDA_CONTROLLER_DEV *HdaDev
741 )
742{
743 EFI_PCI_IO_PROTOCOL *PciIo;
744 HDA_STREAM *HdaStream;
745
746 UINT32 Index;
747 UINT32 Tmp;
748
749 ASSERT (HdaDev != NULL);
750
751 PciIo = HdaDev->PciIo;
752
753 if ((HdaDev->Streams != NULL) && (HdaDev->StreamsCount > 0)) {
754 for (Index = 0; Index < HdaDev->StreamsCount; Index++) {
755 HdaStream = &HdaDev->Streams[Index];
756
757 //
758 // Is stream at a stage where it can be torn down safely?
759 //
760 if (!HdaStream->HasIndex) {
761 break;
762 }
763
764 //
765 // Close poll timer and disable stream.
766 //
767 if (HdaStream->PollTimer != NULL) {
768 gBS->CloseEvent (HdaStream->PollTimer);
769 HdaStream->PollTimer = NULL;
770 }
771
772 HdaControllerSetStreamState (HdaStream, FALSE);
773 HdaControllerSetStreamId (HdaStream, 0);
774
775 //
776 // Unmap and free BDL.
777 //
778 if (HdaStream->BufferListMapping != NULL) {
779 PciIo->Unmap (PciIo, HdaStream->BufferListMapping);
780 }
781
782 if (HdaStream->BufferList != NULL) {
783 PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (HDA_BDL_SIZE), HdaStream->BufferList);
784 }
785
786 //
787 // Unmap and free data buffer.
788 //
789 if (HdaStream->BufferDataMapping != NULL) {
790 PciIo->Unmap (PciIo, HdaStream->BufferDataMapping);
791 }
792
793 if (HdaStream->BufferData != NULL) {
794 PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (HDA_STREAM_BUF_SIZE), HdaStream->BufferData);
795 }
796 }
797 }
798
799 //
800 // Clear DMA positions structure base address.
801 //
802 Tmp = 0;
803 PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, PCI_HDA_BAR, HDA_REG_DPLBASE, 1, &Tmp);
804 if (HdaDev->Capabilities & HDA_REG_GCAP_64OK) {
805 PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, PCI_HDA_BAR, HDA_REG_DPUBASE, 1, &Tmp);
806 }
807
808 //
809 // Unmap and free DMA positions structure.
810 //
811 if (HdaDev->DmaPositionsMapping != NULL) {
812 PciIo->Unmap (PciIo, HdaDev->DmaPositionsMapping);
813 }
814
815 if (HdaDev->DmaPositions != NULL) {
816 PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (HdaDev->DmaPositionsSize), HdaDev->DmaPositions);
817 }
818
819 if (HdaDev->Streams != NULL) {
820 FreePool (HdaDev->Streams);
821 }
822
823 HdaDev->DmaPositionsMapping = NULL;
824 HdaDev->DmaPositions = NULL;
825 HdaDev->DmaPositionsSize = 0;
826 HdaDev->DmaPositionsPhysAddr = 0;
827 HdaDev->Streams = NULL;
828 HdaDev->StreamsCount = 0;
829}
830
831BOOLEAN
833 IN HDA_STREAM *HdaStream,
834 OUT BOOLEAN *Run
835 )
836{
837 EFI_STATUS Status;
838 EFI_PCI_IO_PROTOCOL *PciIo;
839 UINT8 HdaStreamCtl1;
840
841 ASSERT (HdaStream != NULL);
842 ASSERT (Run != NULL);
843
844 PciIo = HdaStream->HdaDev->PciIo;
845
846 //
847 // Get current value of stream control register.
848 //
849 Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, HDA_REG_SDNCTL1 (HdaStream->Index), 1, &HdaStreamCtl1);
850 if (EFI_ERROR (Status)) {
851 return FALSE;
852 }
853
854 *Run = (HdaStreamCtl1 & HDA_REG_SDNCTL1_RUN) != 0;
855 return TRUE;
856}
857
858BOOLEAN
860 IN HDA_STREAM *HdaStream,
861 IN BOOLEAN Run
862 )
863{
864 EFI_STATUS Status;
865 EFI_PCI_IO_PROTOCOL *PciIo;
866 UINT8 HdaStreamCtl1;
867 UINT64 Tmp;
868
869 ASSERT (HdaStream != NULL);
870
871 PciIo = HdaStream->HdaDev->PciIo;
872
873 //
874 // Get current value of stream control register.
875 //
876 Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, HDA_REG_SDNCTL1 (HdaStream->Index), 1, &HdaStreamCtl1);
877 if (EFI_ERROR (Status)) {
878 return FALSE;
879 }
880
881 if (Run) {
882 HdaStreamCtl1 |= HDA_REG_SDNCTL1_RUN;
883 } else {
884 HdaStreamCtl1 &= ~HDA_REG_SDNCTL1_RUN;
885 }
886
887 //
888 // Write updated run bit to stream control register and wait for bit status to change.
889 //
890 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, HDA_REG_SDNCTL1 (HdaStream->Index), 1, &HdaStreamCtl1);
891 if (EFI_ERROR (Status)) {
892 return FALSE;
893 }
894
895 Status = PciIo->PollMem (
896 PciIo,
897 EfiPciIoWidthUint8,
899 HDA_REG_SDNCTL1 (HdaStream->Index),
901 HdaStreamCtl1 & HDA_REG_SDNCTL1_RUN,
903 &Tmp
904 );
905 return !EFI_ERROR (Status);
906}
907
908BOOLEAN
910 IN HDA_STREAM *HdaStream,
911 OUT UINT32 *Position
912 )
913{
914 EFI_STATUS Status;
915 EFI_PCI_IO_PROTOCOL *PciIo;
916
917 ASSERT (HdaStream != NULL);
918 ASSERT (Position != NULL);
919
920 PciIo = HdaStream->HdaDev->PciIo;
921
922 //
923 // Get current value of stream link position register.
924 //
925 Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint32, PCI_HDA_BAR, HDA_REG_SDNLPIB (HdaStream->Index), 1, Position);
926 return !EFI_ERROR (Status);
927}
928
929BOOLEAN
931 IN HDA_STREAM *HdaStream,
932 OUT UINT8 *Index
933 )
934{
935 EFI_STATUS Status;
936 EFI_PCI_IO_PROTOCOL *PciIo;
937 UINT8 HdaStreamCtl3;
938
939 ASSERT (HdaStream != NULL);
940 ASSERT (Index != NULL);
941
942 PciIo = HdaStream->HdaDev->PciIo;
943
944 //
945 // Get current value of stream control register.
946 //
947 Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, HDA_REG_SDNCTL3 (HdaStream->Index), 1, &HdaStreamCtl3);
948 if (EFI_ERROR (Status)) {
949 return FALSE;
950 }
951
952 *Index = HDA_REG_SDNCTL3_STRM_GET (HdaStreamCtl3);
953 return TRUE;
954}
955
956BOOLEAN
958 IN HDA_STREAM *HdaStream,
959 IN UINT8 Index
960 )
961{
962 EFI_STATUS Status;
963 EFI_PCI_IO_PROTOCOL *PciIo;
964 UINT8 HdaStreamCtl3;
965
966 ASSERT (HdaStream != NULL);
967
968 PciIo = HdaStream->HdaDev->PciIo;
969
970 //
971 // Stop stream.
972 //
973 if (!HdaControllerSetStreamState (HdaStream, FALSE)) {
974 return FALSE;
975 }
976
977 //
978 // Get current value of stream control register.
979 //
980 Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, HDA_REG_SDNCTL3 (HdaStream->Index), 1, &HdaStreamCtl3);
981 if (EFI_ERROR (Status)) {
982 return FALSE;
983 }
984
985 //
986 // Update stream index and write stream control register.
987 //
988 HdaStreamCtl3 = HDA_REG_SDNCTL3_STRM_SET (HdaStreamCtl3, Index);
989 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint8, PCI_HDA_BAR, HDA_REG_SDNCTL3 (HdaStream->Index), 1, &HdaStreamCtl3);
990 return !EFI_ERROR (Status);
991}
992
993VOID
995 IN HDA_STREAM *HdaStream
996 )
997{
998 ASSERT (HdaStream != NULL);
999
1000 //
1001 // Reset buffer information to idle stream.
1002 //
1003 HdaStream->BufferActive = FALSE;
1004 HdaStream->BufferSource = NULL;
1005 HdaStream->BufferSourcePosition = 0;
1006 HdaStream->BufferSourceLength = 0;
1007 HdaStream->DmaPositionTotal = 0;
1008
1009 ZeroMem (HdaStream->BufferData, HDA_STREAM_BUF_SIZE);
1010}
1011
1012VOID
1014 IN HDA_STREAM *HdaStream
1015 )
1016{
1017 ASSERT (HdaStream != NULL);
1018
1019 HdaControllerStreamIdle (HdaStream);
1020
1021 //
1022 // Stop stream and timer.
1023 //
1024 HdaControllerSetStreamState (HdaStream, FALSE);
1025 gBS->SetTimer (HdaStream->PollTimer, TimerCancel, 0);
1026
1027 // DEBUG ((DEBUG_INFO, "AudioDxe: Stream %u aborted!\n", HdaStream->Index));
1028}
VOID EFIAPI HdaControllerStreamOutputPollTimerHandler(IN EFI_EVENT Event, IN VOID *Context)
#define HDA_CORB_ENTRY_SIZE
#define HDA_STREAM_BUF_SIZE
#define HDA_BDL_BLOCKSIZE
#define HDA_CONTROLLER_QUIRK_QEMU_1
#define HDA_BDL_ENTRY_COUNT
#define HDA_BDL_SIZE
#define HDA_CONTROLLER_QUIRK_CORB_NO_POLL_RESET
#define HDA_BDL_ENTRY_LAST
#define PCI_HDA_BAR
#define HDA_RIRB_ENTRY_SIZE
HDA_RING_BUFFER_TYPE
@ HDA_RING_BUFFER_TYPE_RIRB
@ HDA_RING_BUFFER_TYPE_CORB
#define HDA_CONTROLLER_QUIRK_QEMU_2
EFI_STATUS HdaControllerSetRingBufferState(IN HDA_RING_BUFFER *HdaRingBuffer, IN BOOLEAN Enable, IN HDA_RING_BUFFER_TYPE Type)
VOID HdaControllerStreamIdle(IN HDA_STREAM *HdaStream)
VOID HdaControllerStreamAbort(IN HDA_STREAM *HdaStream)
EFI_STATUS HdaControllerInitStreams(IN HDA_CONTROLLER_DEV *HdaDev)
BOOLEAN HdaControllerResetStream(IN HDA_STREAM *HdaStream)
BOOLEAN HdaControllerSetStreamId(IN HDA_STREAM *HdaStream, IN UINT8 Index)
BOOLEAN HdaControllerSetStreamState(IN HDA_STREAM *HdaStream, IN BOOLEAN Run)
BOOLEAN HdaControllerGetStreamLinkPos(IN HDA_STREAM *HdaStream, OUT UINT32 *Position)
VOID HdaControllerCleanupRingBuffer(IN HDA_RING_BUFFER *HdaRingBuffer, IN HDA_RING_BUFFER_TYPE Type)
EFI_STATUS HdaControllerResetRingBuffer(IN HDA_RING_BUFFER *HdaRingBuffer)
BOOLEAN HdaControllerGetStreamState(IN HDA_STREAM *HdaStream, OUT BOOLEAN *Run)
EFI_STATUS HdaControllerInitRingBuffer(IN HDA_RING_BUFFER *HdaRingBuffer, IN HDA_CONTROLLER_DEV *HdaDev, IN HDA_RING_BUFFER_TYPE Type)
VOID HdaControllerCleanupStreams(IN HDA_CONTROLLER_DEV *HdaDev)
BOOLEAN HdaControllerGetStreamId(IN HDA_STREAM *HdaStream, OUT UINT8 *Index)
#define HDA_REG_CORB_BASE
#define HDA_REG_SDNCTL3_STRM_GET(a)
#define HDA_REG_SDNCTL3_STRM_SET(a, s)
#define HDA_OFFSET_RING_SIZE_SZCAP_256
#define HDA_OFFSET_RING_UBASE
#define HDA_REG_SDNCTL3_DIR
#define HDA_REG_SDNLVI(n)
#define HDA_REG_CORBRP_RST
#define HDA_OFFSET_RING_SIZE_ENT256
#define HDA_REG_SDNCTL3(n)
#define HDA_OFFSET_RING_SIZE_SZCAP_16
#define HDA_OFFSET_RING_SIZE_ENT16
#define HDA_REG_DPUBASE
#define HDA_REG_SDNCTL1(n)
#define HDA_REG_DPLBASE
#define HDA_REG_SDNBDPL(n)
#define HDA_OFFSET_RING_SIZE_ENT2
#define HDA_REG_SDNBDPU(n)
#define HDA_OFFSET_RING_SIZE_SZCAP_2
#define HDA_REG_RIRBWP_RST
#define HDA_REG_GCAP_ISS(a)
#define HDA_OFFSET_RING_SIZE
#define HDA_REG_SDNCTL1_SRST
#define HDA_OFFSET_RING_BASE
#define HDA_REG_DPLBASE_EN
#define HDA_REG_RINTCNT
#define HDA_REG_SDNCBL(n)
#define HDA_OFFSET_RING_CTL
#define HDA_REG_SDNLPIB(n)
#define HDA_REG_CORBRP
#define HDA_REG_SDNCTL1_RUN
#define HDA_OFFSET_RING_CTL_RUN
#define HDA_REG_GCAP_64OK
#define HDA_REG_RIRBWP
#define HDA_REG_RIRB_BASE
#define HDA_REG_RIRBCTL_RINTCTL
#define HDA_REG_CORBWP
#define HDA_REG_GCAP_OSS(a)
#define HDA_REG_GCAP_BSS(a)
EFI_BOOT_SERVICES * gBS
#define MS_TO_NANOSECONDS(x)
Definition OcMiscLib.h:37
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
#define ASSERT(x)
Definition coder.h:55
UINT32 InterruptOnCompletion
EFI_EVENT PollTimer
UINT8 * BufferData
HDA_BDL_ENTRY * BufferList
BOOLEAN HasIndex
VOID * BufferListMapping
EFI_PHYSICAL_ADDRESS BufferDataPhysAddr
HDA_CONTROLLER_DEV * HdaDev
VOID * BufferDataMapping
EFI_PHYSICAL_ADDRESS BufferListPhysAddr
BOOLEAN IsBidirectional