source: mainline/uspace/drv/audio/hdaudio/hdactl.c@ ad896eb

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ad896eb was 13db2044, checked in by Jakub Jermar <jakub@…>, 7 years ago

Fix unmapping of virtual address of DMA memory

  • Property mode set to 100644
File size: 17.8 KB
Line 
1/*
2 * Copyright (c) 2014 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup hdaudio
30 * @{
31 */
32/** @file High Definition Audio controller
33 */
34
35#include <as.h>
36#include <async.h>
37#include <bitops.h>
38#include <ddf/log.h>
39#include <ddi.h>
40#include <errno.h>
41#include <fibril_synch.h>
42#include <macros.h>
43#include <stdint.h>
44
45#include "codec.h"
46#include "hdactl.h"
47#include "regif.h"
48#include "spec/regs.h"
49
50enum {
51 ctrl_init_wait_max = 10,
52 codec_enum_wait_us = 512,
53 corb_wait_max = 10,
54 rirb_wait_max = 100,
55 solrb_wait_us = 100 * 1000
56};
57
58static void hda_ctl_process_rirb(hda_ctl_t *);
59
60/** Perform set-reset handshake on a 16-bit register.
61 *
62 * The bit(s) specified in the mask are written as 1, then we wait
63 * for them to read as 1. Then we write them as 0 and we wait for them
64 * to read as 0.
65 */
66static errno_t hda_ctl_reg16_set_reset(uint16_t *reg, uint16_t mask)
67{
68 uint16_t val;
69 int wcnt;
70
71 val = hda_reg16_read(reg);
72 hda_reg16_write(reg, val | mask);
73
74 wcnt = 1000;
75 while (wcnt > 0) {
76 val = hda_reg16_read(reg);
77 if ((val & mask) == mask)
78 break;
79
80 async_usleep(1000);
81 --wcnt;
82 }
83
84 if ((val & mask) != mask)
85 return ETIMEOUT;
86
87 val = hda_reg16_read(reg);
88 hda_reg16_write(reg, val & ~mask);
89
90 wcnt = 1000;
91 while (wcnt > 0) {
92 val = hda_reg16_read(reg);
93 if ((val & mask) == 0)
94 break;
95
96 async_usleep(1000);
97 --wcnt;
98 }
99
100 if ((val & mask) != 0)
101 return ETIMEOUT;
102
103 return EOK;
104}
105
106/** Select an appropriate CORB/RIRB size.
107 *
108 * We always use the largest available size. In @a sizecap each of bits
109 * 0, 1, 2 determine whether one of the supported size (0 == 2 entries,
110 * 1 == 16 entries, 2 == 256 entries) is supported. @a *selsz is set to
111 * one of 0, 1, 2 on success.
112 *
113 * @param sizecap CORB/RIRB Size Capability
114 * @param selsz Place to store CORB/RIRB Size
115 * @return EOK on success, EINVAL if sizecap has no valid bits set
116 *
117 */
118static errno_t hda_rb_size_select(uint8_t sizecap, uint8_t *selsz)
119{
120 int i;
121
122 for (i = 2; i >= 0; --i) {
123 if ((sizecap & BIT_V(uint8_t, i)) != 0) {
124 *selsz = i;
125 return EOK;
126 }
127 }
128
129 return EINVAL;
130}
131
132static size_t hda_rb_entries(uint8_t selsz)
133{
134 switch (selsz) {
135 case 0:
136 return 2;
137 case 1:
138 return 16;
139 case 2:
140 return 256;
141 default:
142 assert(false);
143 return 0;
144 }
145}
146
147/** Initialize the CORB */
148static errno_t hda_corb_init(hda_t *hda)
149{
150 uint8_t ctl;
151 uint8_t corbsz;
152 uint8_t sizecap;
153 uint8_t selsz;
154 errno_t rc;
155
156 ddf_msg(LVL_NOTE, "hda_corb_init()");
157
158 /* Stop CORB if not stopped */
159 ctl = hda_reg8_read(&hda->regs->corbctl);
160 if ((ctl & BIT_V(uint8_t, corbctl_run)) != 0) {
161 ddf_msg(LVL_NOTE, "CORB is enabled, disabling first.");
162 hda_reg8_write(&hda->regs->corbctl, ctl & ~BIT_V(uint8_t,
163 corbctl_run));
164 }
165
166 /* Determine CORB size and allocate CORB buffer */
167 corbsz = hda_reg8_read(&hda->regs->corbsize);
168 sizecap = BIT_RANGE_EXTRACT(uint8_t, corbsize_cap_h,
169 corbsize_cap_l, corbsz);
170 rc = hda_rb_size_select(sizecap, &selsz);
171 if (rc != EOK) {
172 ddf_msg(LVL_ERROR, "Invalid CORB Size Capability");
173 goto error;
174 }
175 corbsz = corbsz & ~BIT_RANGE(uint8_t, corbsize_size_h, corbsize_size_l);
176 corbsz = corbsz | selsz;
177
178 ddf_msg(LVL_NOTE, "Setting CORB Size register to 0x%x", corbsz);
179 hda_reg8_write(&hda->regs->corbsize, corbsz);
180 hda->ctl->corb_entries = hda_rb_entries(selsz);
181
182
183 /*
184 * CORB must be aligned to 128 bytes. If 64OK is not set,
185 * it must be within the 32-bit address space.
186 */
187 hda->ctl->corb_virt = AS_AREA_ANY;
188 rc = dmamem_map_anonymous(hda->ctl->corb_entries * sizeof(uint32_t),
189 hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
190 &hda->ctl->corb_phys, &hda->ctl->corb_virt);
191 if (rc != EOK) {
192 hda->ctl->corb_virt = NULL;
193 ddf_msg(LVL_NOTE, "Failed allocating DMA memory for CORB");
194 goto error;
195 }
196
197 ddf_msg(LVL_NOTE, "Set CORB base registers");
198
199 /* Update CORB base registers */
200 hda_reg32_write(&hda->regs->corblbase, LOWER32(hda->ctl->corb_phys));
201 hda_reg32_write(&hda->regs->corbubase, UPPER32(hda->ctl->corb_phys));
202
203 ddf_msg(LVL_NOTE, "Reset CORB Read/Write pointers");
204
205 /* Reset CORB Read Pointer */
206 rc = hda_ctl_reg16_set_reset(&hda->regs->corbrp,
207 BIT_V(uint16_t, corbrp_rst));
208 if (rc != EOK) {
209 ddf_msg(LVL_NOTE, "Failed resetting CORBRP");
210 goto error;
211 }
212
213 /* Reset CORB Write Pointer */
214 hda_reg16_write(&hda->regs->corbwp, 0);
215
216 /* Start CORB */
217 ctl = hda_reg8_read(&hda->regs->corbctl);
218 ddf_msg(LVL_NOTE, "CORBctl (0x%x) = 0x%x",
219 (unsigned)((void *)&hda->regs->corbctl - (void *)hda->regs), ctl | BIT_V(uint8_t, corbctl_run));
220 hda_reg8_write(&hda->regs->corbctl, ctl | BIT_V(uint8_t, corbctl_run));
221
222 ddf_msg(LVL_NOTE, "CORB initialized");
223 return EOK;
224error:
225 if (hda->ctl->corb_virt != NULL) {
226 dmamem_unmap_anonymous(hda->ctl->corb_virt);
227 hda->ctl->corb_virt = NULL;
228 }
229 return EIO;
230}
231
232/** Tear down the CORB */
233static void hda_corb_fini(hda_t *hda)
234{
235 uint8_t ctl;
236
237 /* Stop CORB */
238 ctl = hda_reg8_read(&hda->regs->corbctl);
239 hda_reg8_write(&hda->regs->corbctl, ctl & ~BIT_V(uint8_t, corbctl_run));
240
241 if (hda->ctl->corb_virt != NULL)
242 dmamem_unmap_anonymous(hda->ctl->corb_virt);
243}
244
245/** Initialize the RIRB */
246static errno_t hda_rirb_init(hda_t *hda)
247{
248 uint8_t ctl;
249 uint8_t rirbsz;
250 uint8_t sizecap;
251 uint8_t selsz;
252 errno_t rc;
253
254 ddf_msg(LVL_NOTE, "hda_rirb_init()");
255
256 /* Stop RIRB if not stopped */
257 ctl = hda_reg8_read(&hda->regs->rirbctl);
258 if ((ctl & BIT_V(uint8_t, rirbctl_run)) != 0) {
259 ddf_msg(LVL_NOTE, "RIRB is enabled, disabling first.");
260 hda_reg8_write(&hda->regs->corbctl, ctl & ~BIT_V(uint8_t,
261 rirbctl_run));
262 }
263
264 /* Determine RIRB size and allocate RIRB buffer */
265 rirbsz = hda_reg8_read(&hda->regs->rirbsize);
266 sizecap = BIT_RANGE_EXTRACT(uint8_t, rirbsize_cap_h,
267 rirbsize_cap_l, rirbsz);
268 rc = hda_rb_size_select(sizecap, &selsz);
269 if (rc != EOK) {
270 ddf_msg(LVL_ERROR, "Invalid RIRB Size Capability");
271 goto error;
272 }
273 rirbsz = rirbsz & ~BIT_RANGE(uint8_t, rirbsize_size_h, rirbsize_size_l);
274 rirbsz = rirbsz | (selsz << rirbsize_size_l);
275
276 ddf_msg(LVL_NOTE, "Setting RIRB Size register to 0x%x", rirbsz);
277 hda_reg8_write(&hda->regs->rirbsize, rirbsz);
278 hda->ctl->rirb_entries = hda_rb_entries(selsz);
279
280 /*
281 * RIRB must be aligned to 128 bytes. If 64OK is not set,
282 * it must be within the 32-bit address space.
283 */
284 hda->ctl->rirb_virt = AS_AREA_ANY;
285 rc = dmamem_map_anonymous(hda->ctl->rirb_entries * sizeof(uint64_t),
286 hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
287 &hda->ctl->rirb_phys, &hda->ctl->rirb_virt);
288 if (rc != EOK) {
289 hda->ctl->rirb_virt = NULL;
290 ddf_msg(LVL_NOTE, "Failed allocating DMA memory for RIRB");
291 goto error;
292 }
293
294 ddf_msg(LVL_NOTE, "Set RIRB base registers");
295
296 /* Update RIRB base registers */
297 hda_reg32_write(&hda->regs->rirblbase, LOWER32(hda->ctl->rirb_phys));
298 hda_reg32_write(&hda->regs->rirbubase, UPPER32(hda->ctl->rirb_phys));
299
300 ddf_msg(LVL_NOTE, "Reset RIRB Write pointer");
301
302 /* Reset RIRB Write Pointer */
303 hda_reg16_write(&hda->regs->rirbwp, BIT_V(uint16_t, rirbwp_rst));
304
305 /* Set RINTCNT - Qemu won't read from CORB if this is zero */
306 hda_reg16_write(&hda->regs->rintcnt, hda->ctl->rirb_entries / 2);
307
308 hda->ctl->rirb_rp = 0;
309
310 /* Start RIRB and enable RIRB interrupt */
311 ctl = hda_reg8_read(&hda->regs->rirbctl);
312 ddf_msg(LVL_NOTE, "RIRBctl (0x%x) = 0x%x",
313 (unsigned)((void *)&hda->regs->rirbctl - (void *)hda->regs), ctl | BIT_V(uint8_t, rirbctl_run));
314 hda_reg8_write(&hda->regs->rirbctl, ctl | BIT_V(uint8_t, rirbctl_run) |
315 BIT_V(uint8_t, rirbctl_int));
316
317 ddf_msg(LVL_NOTE, "RIRB initialized");
318 return EOK;
319error:
320 if (hda->ctl->rirb_virt != NULL) {
321 dmamem_unmap_anonymous(hda->ctl->rirb_virt);
322 hda->ctl->rirb_virt = NULL;
323 }
324 return EIO;
325}
326
327/** Tear down the RIRB */
328static void hda_rirb_fini(hda_t *hda)
329{
330 uint8_t ctl;
331
332 /* Stop RIRB and disable RIRB interrupt */
333 ctl = hda_reg8_read(&hda->regs->rirbctl);
334 hda_reg8_write(&hda->regs->rirbctl, ctl &
335 ~(BIT_V(uint8_t, rirbctl_run) | BIT_V(uint8_t, rirbctl_int)));
336
337 if (hda->ctl->rirb_virt != NULL)
338 dmamem_unmap_anonymous(hda->ctl->rirb_virt);
339}
340
341static size_t hda_get_corbrp(hda_t *hda)
342{
343 uint16_t corbrp;
344
345 corbrp = hda_reg16_read(&hda->regs->corbrp);
346 return BIT_RANGE_EXTRACT(uint16_t, corbrp_rp_h, corbrp_rp_l, corbrp);
347}
348
349static size_t hda_get_corbwp(hda_t *hda)
350{
351 uint16_t corbwp;
352
353 corbwp = hda_reg16_read(&hda->regs->corbwp);
354 return BIT_RANGE_EXTRACT(uint16_t, corbwp_wp_h, corbwp_wp_l, corbwp);
355}
356
357static void hda_set_corbwp(hda_t *hda, size_t wp)
358{
359 ddf_msg(LVL_DEBUG2, "Set CORBWP = %zu", wp);
360 hda_reg16_write(&hda->regs->corbwp, wp);
361}
362
363static size_t hda_get_rirbwp(hda_t *hda)
364{
365 uint16_t rirbwp;
366
367 rirbwp = hda_reg16_read(&hda->regs->rirbwp);
368 return BIT_RANGE_EXTRACT(uint16_t, rirbwp_wp_h, rirbwp_wp_l, rirbwp);
369}
370
371/** Determine number of free entries in CORB */
372static size_t hda_corb_avail(hda_t *hda)
373{
374 int rp, wp;
375 int avail;
376
377 rp = hda_get_corbrp(hda);
378 wp = hda_get_corbwp(hda);
379
380 avail = rp - wp - 1;
381 while (avail < 0)
382 avail += hda->ctl->corb_entries;
383
384 return avail;
385}
386
387/** Write to CORB */
388static errno_t hda_corb_write(hda_t *hda, uint32_t *data, size_t count)
389{
390 size_t avail;
391 size_t wp;
392 size_t idx;
393 size_t now;
394 size_t i;
395 uint32_t *corb;
396 int wcnt;
397
398 avail = hda_corb_avail(hda);
399 wp = hda_get_corbwp(hda);
400 corb = (uint32_t *)hda->ctl->corb_virt;
401
402 idx = 0;
403 while (idx < count) {
404 now = min(avail, count - idx);
405
406 for (i = 0; i < now; i++) {
407 wp = (wp + 1) % hda->ctl->corb_entries;
408 corb[wp] = data[idx++];
409 }
410
411 hda_set_corbwp(hda, wp);
412
413 if (idx < count) {
414 /* We filled up CORB but still data remaining */
415 wcnt = corb_wait_max;
416 while (hda_corb_avail(hda) < 1 && wcnt > 0) {
417 async_usleep(100);
418 --wcnt;
419 }
420
421 /* If CORB is still full return timeout error */
422 if (hda_corb_avail(hda) < 1)
423 return ETIMEOUT;
424 }
425 }
426
427 return EOK;
428}
429
430static errno_t hda_rirb_read(hda_t *hda, hda_rirb_entry_t *data)
431{
432 size_t wp;
433 hda_rirb_entry_t resp;
434 hda_rirb_entry_t *rirb;
435
436 rirb = (hda_rirb_entry_t *)hda->ctl->rirb_virt;
437
438 wp = hda_get_rirbwp(hda);
439 ddf_msg(LVL_DEBUG2, "hda_rirb_read: wp=%zu", wp);
440 if (hda->ctl->rirb_rp == wp)
441 return ENOENT;
442
443 hda->ctl->rirb_rp = (hda->ctl->rirb_rp + 1) % hda->ctl->rirb_entries;
444 resp = rirb[hda->ctl->rirb_rp];
445
446 ddf_msg(LVL_DEBUG2, "RESPONSE resp=0x%x respex=0x%x",
447 resp.resp, resp.respex);
448 *data = resp;
449 return EOK;
450}
451
452static errno_t hda_solrb_read(hda_t *hda, hda_rirb_entry_t *data, size_t count)
453{
454 hda_rirb_entry_t resp;
455
456 ddf_msg(LVL_DEBUG, "hda_solrb_read()");
457
458 fibril_mutex_lock(&hda->ctl->solrb_lock);
459
460 while (count > 0) {
461 while (count > 0 && hda->ctl->solrb_rp != hda->ctl->solrb_wp) {
462 hda->ctl->solrb_rp = (hda->ctl->solrb_rp + 1) % softrb_entries;
463 resp = hda->ctl->solrb[hda->ctl->solrb_rp];
464
465 ddf_msg(LVL_DEBUG2, "solrb RESPONSE resp=0x%x respex=0x%x",
466 resp.resp, resp.respex);
467 if ((resp.respex & BIT_V(uint32_t, respex_unsol)) == 0) {
468 /* Solicited response */
469 *data++ = resp;
470 --count;
471 }
472 }
473
474 if (count > 0) {
475 if (hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
476 fibril_condvar_wait_timeout(
477 &hda->ctl->solrb_cv, &hda->ctl->solrb_lock,
478 solrb_wait_us);
479 }
480
481 if (hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
482 ddf_msg(LVL_NOTE, "hda_solrb_read() - last ditch effort process RIRB");
483 fibril_mutex_unlock(&hda->ctl->solrb_lock);
484 hda_ctl_process_rirb(hda->ctl);
485 fibril_mutex_lock(&hda->ctl->solrb_lock);
486 }
487
488 if (hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
489 ddf_msg(LVL_NOTE, "hda_solrb_read() time out");
490 fibril_mutex_unlock(&hda->ctl->solrb_lock);
491 return ETIMEOUT;
492 }
493 }
494 }
495
496 fibril_mutex_unlock(&hda->ctl->solrb_lock);
497 return EOK;
498}
499
500hda_ctl_t *hda_ctl_init(hda_t *hda)
501{
502 hda_ctl_t *ctl;
503 uint32_t gctl;
504 uint32_t intctl;
505 int cnt;
506 errno_t rc;
507
508 ctl = calloc(1, sizeof(hda_ctl_t));
509 if (ctl == NULL)
510 return NULL;
511
512 fibril_mutex_initialize(&ctl->solrb_lock);
513 fibril_condvar_initialize(&ctl->solrb_cv);
514
515 hda->ctl = ctl;
516 ctl->hda = hda;
517
518 uint8_t vmaj = hda_reg8_read(&hda->regs->vmaj);
519 uint8_t vmin = hda_reg8_read(&hda->regs->vmin);
520 ddf_msg(LVL_NOTE, "HDA version %d.%d", vmaj, vmin);
521
522 if (vmaj != 1 || vmin != 0) {
523 ddf_msg(LVL_ERROR, "Unsupported HDA version (%d.%d).",
524 vmaj, vmin);
525 goto error;
526 }
527
528 ddf_msg(LVL_NOTE, "reg 0x%zx STATESTS = 0x%x",
529 (void *)&hda->regs->statests - (void *)hda->regs,
530 hda_reg16_read(&hda->regs->statests));
531 /**
532 * Clear STATESTS bits so they don't generate an interrupt later
533 * when we enable interrupts.
534 */
535 hda_reg16_write(&hda->regs->statests, 0x7f);
536
537 ddf_msg(LVL_NOTE, "after clearing reg 0x%zx STATESTS = 0x%x",
538 (void *)&hda->regs->statests - (void *)hda->regs,
539 hda_reg16_read(&hda->regs->statests));
540
541 gctl = hda_reg32_read(&hda->regs->gctl);
542 if ((gctl & BIT_V(uint32_t, gctl_crst)) != 0) {
543 ddf_msg(LVL_NOTE, "Controller not in reset. Resetting.");
544 hda_reg32_write(&hda->regs->gctl, gctl & ~BIT_V(uint32_t, gctl_crst));
545 }
546
547 ddf_msg(LVL_NOTE, "Taking controller out of reset.");
548 hda_reg32_write(&hda->regs->gctl, gctl | BIT_V(uint32_t, gctl_crst));
549
550 /* Wait for CRST to read as 1 */
551 cnt = ctrl_init_wait_max;
552 while (cnt > 0) {
553 gctl = hda_reg32_read(&hda->regs->gctl);
554 if ((gctl & BIT_V(uint32_t, gctl_crst)) != 0) {
555 ddf_msg(LVL_NOTE, "gctl=0x%x", gctl);
556 break;
557 }
558
559 ddf_msg(LVL_NOTE, "Waiting for controller to initialize.");
560 async_usleep(100 * 1000);
561 --cnt;
562 }
563
564 if (cnt == 0) {
565 ddf_msg(LVL_ERROR, "Timed out waiting for controller to come up.");
566 goto error;
567 }
568
569 ddf_msg(LVL_NOTE, "Controller is out of reset.");
570
571 ddf_msg(LVL_NOTE, "Read GCAP");
572 uint16_t gcap = hda_reg16_read(&hda->regs->gcap);
573 ctl->ok64bit = (gcap & BIT_V(uint16_t, gcap_64ok)) != 0;
574 ctl->oss = BIT_RANGE_EXTRACT(uint16_t, gcap_oss_h, gcap_oss_l, gcap);
575 ctl->iss = BIT_RANGE_EXTRACT(uint16_t, gcap_iss_h, gcap_iss_l, gcap);
576 ctl->bss = BIT_RANGE_EXTRACT(uint16_t, gcap_bss_h, gcap_bss_l, gcap);
577 ddf_msg(LVL_NOTE, "GCAP: 0x%x (64OK=%d)", gcap, ctl->ok64bit);
578 ddf_msg(LVL_NOTE, "iss: %d, oss: %d, bss: %d\n",
579 ctl->iss, ctl->oss, ctl->bss);
580 /* Give codecs enough time to enumerate themselves */
581 async_usleep(codec_enum_wait_us);
582
583 ddf_msg(LVL_NOTE, "STATESTS = 0x%x",
584 hda_reg16_read(&hda->regs->statests));
585
586 /* Enable interrupts */
587 intctl = hda_reg32_read(&hda->regs->intctl);
588 ddf_msg(LVL_NOTE, "intctl (0x%x) := 0x%x",
589 (unsigned)((void *)&hda->regs->intctl - (void *)hda->regs),
590 intctl | BIT_V(uint32_t, intctl_gie) | BIT_V(uint32_t, intctl_cie));
591 hda_reg32_write(&hda->regs->intctl, intctl |
592 BIT_V(uint32_t, intctl_gie) | BIT_V(uint32_t, intctl_cie) |
593 0x3fffffff);
594
595 rc = hda_corb_init(hda);
596 if (rc != EOK)
597 goto error;
598
599 rc = hda_rirb_init(hda);
600 if (rc != EOK)
601 goto error;
602
603 ddf_msg(LVL_NOTE, "call hda_codec_init()");
604 hda->ctl->codec = hda_codec_init(hda, 0);
605 if (hda->ctl->codec == NULL) {
606 ddf_msg(LVL_NOTE, "hda_codec_init() failed");
607 goto error;
608 }
609
610 ddf_msg(LVL_NOTE, "intsts=0x%x", hda_reg32_read(&hda->regs->intsts));
611 ddf_msg(LVL_NOTE, "sdesc[%d].sts=0x%x",
612 hda->ctl->iss, hda_reg8_read(&hda->regs->sdesc[hda->ctl->iss].sts));
613
614 return ctl;
615error:
616 hda_rirb_fini(hda);
617 hda_corb_fini(hda);
618 free(ctl);
619 hda->ctl = NULL;
620 return NULL;
621}
622
623void hda_ctl_fini(hda_ctl_t *ctl)
624{
625 ddf_msg(LVL_NOTE, "hda_ctl_fini()");
626 hda_rirb_fini(ctl->hda);
627 hda_corb_fini(ctl->hda);
628 free(ctl);
629}
630
631errno_t hda_cmd(hda_t *hda, uint32_t verb, uint32_t *resp)
632{
633 errno_t rc;
634 hda_rirb_entry_t rentry;
635
636 rc = hda_corb_write(hda, &verb, 1);
637 if (rc != EOK)
638 return rc;
639
640 if (resp != NULL) {
641 rc = hda_solrb_read(hda, &rentry, 1);
642 if (rc != EOK)
643 return rc;
644
645 /* XXX Verify that response came from the correct codec */
646 *resp = rentry.resp;
647 }
648
649 return EOK;
650}
651
652static void hda_ctl_process_rirb(hda_ctl_t *ctl)
653{
654 hda_rirb_entry_t resp;
655 errno_t rc;
656
657 while (true) {
658 rc = hda_rirb_read(ctl->hda, &resp);
659 if (rc != EOK) {
660 ddf_msg(LVL_DEBUG2, "nothing in rirb");
661 break;
662 }
663
664 ddf_msg(LVL_DEBUG2, "writing to solrb");
665 fibril_mutex_lock(&ctl->solrb_lock);
666 ctl->solrb_wp = (ctl->solrb_wp + 1) % softrb_entries;
667 ctl->solrb[ctl->solrb_wp] = resp;
668 fibril_mutex_unlock(&ctl->solrb_lock);
669 fibril_condvar_broadcast(&ctl->solrb_cv);
670 }
671}
672
673void hda_ctl_interrupt(hda_ctl_t *ctl)
674{
675 hda_ctl_process_rirb(ctl);
676}
677
678void hda_ctl_dump_info(hda_ctl_t *ctl)
679{
680 ddf_msg(LVL_NOTE, "corbwp=%d, corbrp=%d",
681 hda_reg16_read(&ctl->hda->regs->corbwp),
682 hda_reg16_read(&ctl->hda->regs->corbrp));
683 ddf_msg(LVL_NOTE, "corbctl=0x%x, corbsts=0x%x",
684 hda_reg8_read(&ctl->hda->regs->corbctl),
685 hda_reg8_read(&ctl->hda->regs->corbsts));
686 ddf_msg(LVL_NOTE, "rirbwp=0x%x, soft-rirbrp=0x%zx",
687 hda_reg16_read(&ctl->hda->regs->rirbwp),
688 ctl->rirb_rp);
689 ddf_msg(LVL_NOTE, "solrb_wp=0x%zx, solrb_rp=0x%zx",
690 ctl->solrb_wp, ctl->solrb_wp);
691}
692
693/** @}
694 */
Note: See TracBrowser for help on using the repository browser.