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

Last change on this file was a64970e1, checked in by Jiri Svoboda <jiri@…>, 4 months ago

Implement quiesce in HD Audio and SB16 drivers.

  • Property mode set to 100644
File size: 18.6 KB
Line 
1/*
2 * Copyright (c) 2025 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 fibril_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 fibril_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_DEBUG, "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_DEBUG, "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_DEBUG, "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 * CORB must be aligned to 128 bytes. If 64OK is not set,
184 * it must be within the 32-bit address space.
185 */
186 hda->ctl->corb_virt = AS_AREA_ANY;
187 rc = dmamem_map_anonymous(hda->ctl->corb_entries * sizeof(uint32_t),
188 hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
189 &hda->ctl->corb_phys, &hda->ctl->corb_virt);
190 if (rc != EOK) {
191 hda->ctl->corb_virt = NULL;
192 ddf_msg(LVL_ERROR, "Failed allocating DMA memory for CORB");
193 goto error;
194 }
195
196 ddf_msg(LVL_DEBUG, "Set CORB base registers");
197
198 /* Update CORB base registers */
199 hda_reg32_write(&hda->regs->corblbase, LOWER32(hda->ctl->corb_phys));
200 hda_reg32_write(&hda->regs->corbubase, UPPER32(hda->ctl->corb_phys));
201
202 ddf_msg(LVL_DEBUG, "Reset CORB Read/Write pointers");
203
204 /* Reset CORB Read Pointer */
205 rc = hda_ctl_reg16_set_reset(&hda->regs->corbrp,
206 BIT_V(uint16_t, corbrp_rst));
207 if (rc != EOK) {
208 ddf_msg(LVL_ERROR, "Failed resetting CORBRP");
209 goto error;
210 }
211
212 /* Reset CORB Write Pointer */
213 hda_reg16_write(&hda->regs->corbwp, 0);
214
215 /* Start CORB */
216 ctl = hda_reg8_read(&hda->regs->corbctl);
217 ddf_msg(LVL_DEBUG, "CORBctl (0x%x) = 0x%x",
218 (unsigned)((void *)&hda->regs->corbctl - (void *)hda->regs), ctl | BIT_V(uint8_t, corbctl_run));
219 hda_reg8_write(&hda->regs->corbctl, ctl | BIT_V(uint8_t, corbctl_run));
220
221 ddf_msg(LVL_DEBUG, "CORB initialized");
222 return EOK;
223error:
224 if (hda->ctl->corb_virt != NULL) {
225 dmamem_unmap_anonymous(hda->ctl->corb_virt);
226 hda->ctl->corb_virt = NULL;
227 }
228 return EIO;
229}
230
231/** Tear down the CORB */
232static void hda_corb_fini(hda_t *hda)
233{
234 uint8_t ctl;
235
236 /* Stop CORB */
237 ctl = hda_reg8_read(&hda->regs->corbctl);
238 hda_reg8_write(&hda->regs->corbctl, ctl & ~BIT_V(uint8_t, corbctl_run));
239
240 if (hda->ctl->corb_virt != NULL)
241 dmamem_unmap_anonymous(hda->ctl->corb_virt);
242}
243
244/** Initialize the RIRB */
245static errno_t hda_rirb_init(hda_t *hda)
246{
247 uint8_t ctl;
248 uint8_t rirbsz;
249 uint8_t sizecap;
250 uint8_t selsz;
251 errno_t rc;
252
253 ddf_msg(LVL_DEBUG, "hda_rirb_init()");
254
255 /* Stop RIRB if not stopped */
256 ctl = hda_reg8_read(&hda->regs->rirbctl);
257 if ((ctl & BIT_V(uint8_t, rirbctl_run)) != 0) {
258 ddf_msg(LVL_DEBUG, "RIRB is enabled, disabling first.");
259 hda_reg8_write(&hda->regs->corbctl, ctl & ~BIT_V(uint8_t,
260 rirbctl_run));
261 }
262
263 /* Determine RIRB size and allocate RIRB buffer */
264 rirbsz = hda_reg8_read(&hda->regs->rirbsize);
265 sizecap = BIT_RANGE_EXTRACT(uint8_t, rirbsize_cap_h,
266 rirbsize_cap_l, rirbsz);
267 rc = hda_rb_size_select(sizecap, &selsz);
268 if (rc != EOK) {
269 ddf_msg(LVL_ERROR, "Invalid RIRB Size Capability");
270 goto error;
271 }
272 rirbsz = rirbsz & ~BIT_RANGE(uint8_t, rirbsize_size_h, rirbsize_size_l);
273 rirbsz = rirbsz | (selsz << rirbsize_size_l);
274
275 ddf_msg(LVL_DEBUG, "Setting RIRB Size register to 0x%x", rirbsz);
276 hda_reg8_write(&hda->regs->rirbsize, rirbsz);
277 hda->ctl->rirb_entries = hda_rb_entries(selsz);
278
279 /*
280 * RIRB must be aligned to 128 bytes. If 64OK is not set,
281 * it must be within the 32-bit address space.
282 */
283 hda->ctl->rirb_virt = AS_AREA_ANY;
284 rc = dmamem_map_anonymous(hda->ctl->rirb_entries * sizeof(uint64_t),
285 hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
286 &hda->ctl->rirb_phys, &hda->ctl->rirb_virt);
287 if (rc != EOK) {
288 hda->ctl->rirb_virt = NULL;
289 ddf_msg(LVL_ERROR, "Failed allocating DMA memory for RIRB");
290 goto error;
291 }
292
293 ddf_msg(LVL_DEBUG, "Set RIRB base registers");
294
295 /* Update RIRB base registers */
296 hda_reg32_write(&hda->regs->rirblbase, LOWER32(hda->ctl->rirb_phys));
297 hda_reg32_write(&hda->regs->rirbubase, UPPER32(hda->ctl->rirb_phys));
298
299 ddf_msg(LVL_DEBUG, "Reset RIRB Write pointer");
300
301 /* Reset RIRB Write Pointer */
302 hda_reg16_write(&hda->regs->rirbwp, BIT_V(uint16_t, rirbwp_rst));
303
304 /* Set RINTCNT - Qemu won't read from CORB if this is zero */
305 hda_reg16_write(&hda->regs->rintcnt, hda->ctl->rirb_entries / 2);
306
307 hda->ctl->rirb_rp = 0;
308
309 /* Start RIRB and enable RIRB interrupt */
310 ctl = hda_reg8_read(&hda->regs->rirbctl);
311 ddf_msg(LVL_DEBUG, "RIRBctl (0x%x) = 0x%x",
312 (unsigned)((void *)&hda->regs->rirbctl - (void *)hda->regs), ctl | BIT_V(uint8_t, rirbctl_run));
313 hda_reg8_write(&hda->regs->rirbctl, ctl | BIT_V(uint8_t, rirbctl_run) |
314 BIT_V(uint8_t, rirbctl_int));
315
316 ddf_msg(LVL_DEBUG, "RIRB initialized");
317 return EOK;
318error:
319 if (hda->ctl->rirb_virt != NULL) {
320 dmamem_unmap_anonymous(hda->ctl->rirb_virt);
321 hda->ctl->rirb_virt = NULL;
322 }
323 return EIO;
324}
325
326/** Tear down the RIRB */
327static void hda_rirb_fini(hda_t *hda)
328{
329 uint8_t ctl;
330
331 /* Stop RIRB and disable RIRB interrupt */
332 ctl = hda_reg8_read(&hda->regs->rirbctl);
333 hda_reg8_write(&hda->regs->rirbctl, ctl &
334 ~(BIT_V(uint8_t, rirbctl_run) | BIT_V(uint8_t, rirbctl_int)));
335
336 if (hda->ctl->rirb_virt != NULL)
337 dmamem_unmap_anonymous(hda->ctl->rirb_virt);
338}
339
340static size_t hda_get_corbrp(hda_t *hda)
341{
342 uint16_t corbrp;
343
344 corbrp = hda_reg16_read(&hda->regs->corbrp);
345 return BIT_RANGE_EXTRACT(uint16_t, corbrp_rp_h, corbrp_rp_l, corbrp);
346}
347
348static size_t hda_get_corbwp(hda_t *hda)
349{
350 uint16_t corbwp;
351
352 corbwp = hda_reg16_read(&hda->regs->corbwp);
353 return BIT_RANGE_EXTRACT(uint16_t, corbwp_wp_h, corbwp_wp_l, corbwp);
354}
355
356static void hda_set_corbwp(hda_t *hda, size_t wp)
357{
358 ddf_msg(LVL_DEBUG2, "Set CORBWP = %zu", wp);
359 hda_reg16_write(&hda->regs->corbwp, wp);
360}
361
362static size_t hda_get_rirbwp(hda_t *hda)
363{
364 uint16_t rirbwp;
365
366 rirbwp = hda_reg16_read(&hda->regs->rirbwp);
367 return BIT_RANGE_EXTRACT(uint16_t, rirbwp_wp_h, rirbwp_wp_l, rirbwp);
368}
369
370/** Determine number of free entries in CORB */
371static size_t hda_corb_avail(hda_t *hda)
372{
373 int rp, wp;
374 int avail;
375
376 rp = hda_get_corbrp(hda);
377 wp = hda_get_corbwp(hda);
378
379 avail = rp - wp - 1;
380 while (avail < 0)
381 avail += hda->ctl->corb_entries;
382
383 return avail;
384}
385
386/** Write to CORB */
387static errno_t hda_corb_write(hda_t *hda, uint32_t *data, size_t count)
388{
389 size_t avail;
390 size_t wp;
391 size_t idx;
392 size_t now;
393 size_t i;
394 uint32_t *corb;
395 int wcnt;
396
397 avail = hda_corb_avail(hda);
398 wp = hda_get_corbwp(hda);
399 corb = (uint32_t *)hda->ctl->corb_virt;
400
401 idx = 0;
402 while (idx < count) {
403 now = min(avail, count - idx);
404
405 for (i = 0; i < now; i++) {
406 wp = (wp + 1) % hda->ctl->corb_entries;
407 corb[wp] = data[idx++];
408 }
409
410 hda_set_corbwp(hda, wp);
411
412 if (idx < count) {
413 /* We filled up CORB but still data remaining */
414 wcnt = corb_wait_max;
415 while (hda_corb_avail(hda) < 1 && wcnt > 0) {
416 fibril_usleep(100);
417 --wcnt;
418 }
419
420 /* If CORB is still full return timeout error */
421 if (hda_corb_avail(hda) < 1)
422 return ETIMEOUT;
423 }
424 }
425
426 return EOK;
427}
428
429static errno_t hda_rirb_read(hda_t *hda, hda_rirb_entry_t *data)
430{
431 size_t wp;
432 hda_rirb_entry_t resp;
433 hda_rirb_entry_t *rirb;
434
435 rirb = (hda_rirb_entry_t *)hda->ctl->rirb_virt;
436
437 wp = hda_get_rirbwp(hda);
438 ddf_msg(LVL_DEBUG2, "hda_rirb_read: wp=%zu", wp);
439 if (hda->ctl->rirb_rp == wp)
440 return ENOENT;
441
442 hda->ctl->rirb_rp = (hda->ctl->rirb_rp + 1) % hda->ctl->rirb_entries;
443 resp = rirb[hda->ctl->rirb_rp];
444
445 ddf_msg(LVL_DEBUG2, "RESPONSE resp=0x%x respex=0x%x",
446 resp.resp, resp.respex);
447 *data = resp;
448 return EOK;
449}
450
451static errno_t hda_solrb_read(hda_t *hda, hda_rirb_entry_t *data, size_t count)
452{
453 hda_rirb_entry_t resp;
454
455 ddf_msg(LVL_DEBUG, "hda_solrb_read()");
456
457 fibril_mutex_lock(&hda->ctl->solrb_lock);
458
459 while (count > 0) {
460 while (count > 0 && hda->ctl->solrb_rp != hda->ctl->solrb_wp) {
461 hda->ctl->solrb_rp = (hda->ctl->solrb_rp + 1) % softrb_entries;
462 resp = hda->ctl->solrb[hda->ctl->solrb_rp];
463
464 ddf_msg(LVL_DEBUG2, "solrb RESPONSE resp=0x%x respex=0x%x",
465 resp.resp, resp.respex);
466 if ((resp.respex & BIT_V(uint32_t, respex_unsol)) == 0) {
467 /* Solicited response */
468 *data++ = resp;
469 --count;
470 }
471 }
472
473 if (count > 0) {
474 if (hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
475 fibril_condvar_wait_timeout(
476 &hda->ctl->solrb_cv, &hda->ctl->solrb_lock,
477 solrb_wait_us);
478 }
479
480 if (hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
481 ddf_msg(LVL_DEBUG, "hda_solrb_read() - last ditch effort process RIRB");
482 fibril_mutex_unlock(&hda->ctl->solrb_lock);
483 hda_ctl_process_rirb(hda->ctl);
484 fibril_mutex_lock(&hda->ctl->solrb_lock);
485 }
486
487 if (hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
488 ddf_msg(LVL_DEBUG, "hda_solrb_read() time out");
489 fibril_mutex_unlock(&hda->ctl->solrb_lock);
490 return ETIMEOUT;
491 }
492 }
493 }
494
495 fibril_mutex_unlock(&hda->ctl->solrb_lock);
496 return EOK;
497}
498
499hda_ctl_t *hda_ctl_init(hda_t *hda)
500{
501 hda_ctl_t *ctl;
502 uint32_t gctl;
503 uint32_t intctl;
504 int cnt;
505 errno_t rc;
506
507 ctl = calloc(1, sizeof(hda_ctl_t));
508 if (ctl == NULL)
509 return NULL;
510
511 fibril_mutex_initialize(&ctl->solrb_lock);
512 fibril_condvar_initialize(&ctl->solrb_cv);
513
514 hda->ctl = ctl;
515 ctl->hda = hda;
516
517 uint8_t vmaj = hda_reg8_read(&hda->regs->vmaj);
518 uint8_t vmin = hda_reg8_read(&hda->regs->vmin);
519 ddf_msg(LVL_NOTE, "HDA version %d.%d", vmaj, vmin);
520
521 if (vmaj != 1 || vmin != 0) {
522 ddf_msg(LVL_ERROR, "Unsupported HDA version (%d.%d).",
523 vmaj, vmin);
524 goto error;
525 }
526
527 ddf_msg(LVL_DEBUG, "reg 0x%zx STATESTS = 0x%x",
528 (void *)&hda->regs->statests - (void *)hda->regs,
529 hda_reg16_read(&hda->regs->statests));
530 /**
531 * Clear STATESTS bits so they don't generate an interrupt later
532 * when we enable interrupts.
533 */
534 hda_reg16_write(&hda->regs->statests, 0x7f);
535
536 ddf_msg(LVL_DEBUG, "after clearing reg 0x%zx STATESTS = 0x%x",
537 (void *)&hda->regs->statests - (void *)hda->regs,
538 hda_reg16_read(&hda->regs->statests));
539
540 gctl = hda_reg32_read(&hda->regs->gctl);
541 if ((gctl & BIT_V(uint32_t, gctl_crst)) != 0) {
542 ddf_msg(LVL_DEBUG, "Controller not in reset. Resetting.");
543 hda_reg32_write(&hda->regs->gctl, gctl & ~BIT_V(uint32_t, gctl_crst));
544 }
545
546 ddf_msg(LVL_DEBUG, "Taking controller out of reset.");
547 hda_reg32_write(&hda->regs->gctl, gctl | BIT_V(uint32_t, gctl_crst));
548
549 /* Wait for CRST to read as 1 */
550 cnt = ctrl_init_wait_max;
551 while (cnt > 0) {
552 gctl = hda_reg32_read(&hda->regs->gctl);
553 if ((gctl & BIT_V(uint32_t, gctl_crst)) != 0) {
554 ddf_msg(LVL_DEBUG, "gctl=0x%x", gctl);
555 break;
556 }
557
558 ddf_msg(LVL_DEBUG, "Waiting for controller to initialize.");
559 fibril_usleep(100 * 1000);
560 --cnt;
561 }
562
563 if (cnt == 0) {
564 ddf_msg(LVL_ERROR, "Timed out waiting for controller to come up.");
565 goto error;
566 }
567
568 ddf_msg(LVL_DEBUG, "Controller is out of reset.");
569
570 ddf_msg(LVL_DEBUG, "Read GCAP");
571 uint16_t gcap = hda_reg16_read(&hda->regs->gcap);
572 ctl->ok64bit = (gcap & BIT_V(uint16_t, gcap_64ok)) != 0;
573 ctl->oss = BIT_RANGE_EXTRACT(uint16_t, gcap_oss_h, gcap_oss_l, gcap);
574 ctl->iss = BIT_RANGE_EXTRACT(uint16_t, gcap_iss_h, gcap_iss_l, gcap);
575 ctl->bss = BIT_RANGE_EXTRACT(uint16_t, gcap_bss_h, gcap_bss_l, gcap);
576 ddf_msg(LVL_DEBUG, "GCAP: 0x%x (64OK=%d)", gcap, ctl->ok64bit);
577 ddf_msg(LVL_DEBUG, "iss: %d, oss: %d, bss: %d\n",
578 ctl->iss, ctl->oss, ctl->bss);
579 /* Give codecs enough time to enumerate themselves */
580 fibril_usleep(codec_enum_wait_us);
581
582 ddf_msg(LVL_DEBUG, "STATESTS = 0x%x",
583 hda_reg16_read(&hda->regs->statests));
584
585 /* Enable interrupts */
586 intctl = hda_reg32_read(&hda->regs->intctl);
587 ddf_msg(LVL_DEBUG, "intctl (0x%x) := 0x%x",
588 (unsigned)((void *)&hda->regs->intctl - (void *)hda->regs),
589 intctl | BIT_V(uint32_t, intctl_gie) | BIT_V(uint32_t, intctl_cie));
590 hda_reg32_write(&hda->regs->intctl, intctl |
591 BIT_V(uint32_t, intctl_gie) | BIT_V(uint32_t, intctl_cie) |
592 0x3fffffff);
593
594 rc = hda_corb_init(hda);
595 if (rc != EOK)
596 goto error;
597
598 rc = hda_rirb_init(hda);
599 if (rc != EOK)
600 goto error;
601
602 ddf_msg(LVL_DEBUG, "call hda_codec_init()");
603 hda->ctl->codec = hda_codec_init(hda, 0);
604 if (hda->ctl->codec == NULL) {
605 ddf_msg(LVL_DEBUG, "hda_codec_init() failed");
606 goto error;
607 }
608
609 ddf_msg(LVL_DEBUG, "intsts=0x%x", hda_reg32_read(&hda->regs->intsts));
610 ddf_msg(LVL_DEBUG, "sdesc[%d].sts=0x%x",
611 hda->ctl->iss, hda_reg8_read(&hda->regs->sdesc[hda->ctl->iss].sts));
612
613 return ctl;
614error:
615 hda_rirb_fini(hda);
616 hda_corb_fini(hda);
617 free(ctl);
618 hda->ctl = NULL;
619 return NULL;
620}
621
622void hda_ctl_fini(hda_ctl_t *ctl)
623{
624 ddf_msg(LVL_DEBUG, "hda_ctl_fini()");
625 hda_rirb_fini(ctl->hda);
626 hda_corb_fini(ctl->hda);
627 free(ctl);
628}
629
630void hda_ctl_quiesce(hda_ctl_t *ctl)
631{
632 uint32_t gctl;
633
634 ddf_msg(LVL_DEBUG, "hda_ctl_quiesce(): Resetting controller.");
635 gctl = hda_reg32_read(&ctl->hda->regs->gctl);
636 hda_reg32_write(&ctl->hda->regs->gctl,
637 gctl & ~BIT_V(uint32_t, gctl_crst));
638}
639
640errno_t hda_cmd(hda_t *hda, uint32_t verb, uint32_t *resp)
641{
642 errno_t rc;
643 hda_rirb_entry_t rentry;
644
645 rc = hda_corb_write(hda, &verb, 1);
646 if (rc != EOK)
647 return rc;
648
649 if (resp != NULL) {
650 rc = hda_solrb_read(hda, &rentry, 1);
651 if (rc != EOK)
652 return rc;
653
654 /* XXX Verify that response came from the correct codec */
655 *resp = rentry.resp;
656 }
657
658 return EOK;
659}
660
661static void hda_ctl_process_rirb(hda_ctl_t *ctl)
662{
663 hda_rirb_entry_t resp;
664 errno_t rc;
665
666 while (true) {
667 rc = hda_rirb_read(ctl->hda, &resp);
668 if (rc != EOK) {
669 ddf_msg(LVL_DEBUG2, "nothing in rirb");
670 break;
671 }
672
673 ddf_msg(LVL_DEBUG2, "writing to solrb");
674 fibril_mutex_lock(&ctl->solrb_lock);
675 ctl->solrb_wp = (ctl->solrb_wp + 1) % softrb_entries;
676 ctl->solrb[ctl->solrb_wp] = resp;
677 fibril_mutex_unlock(&ctl->solrb_lock);
678 fibril_condvar_broadcast(&ctl->solrb_cv);
679 }
680}
681
682static void hda_ctl_check_fifo_error(hda_ctl_t *ctl)
683{
684 int i;
685 uint8_t sts;
686
687 /*
688 * XXX Ideally the interrupt handler would tell us which stream
689 * has the error.
690 */
691
692 for (i = 0; i < 30; i++) {
693 sts = hda_reg8_read(&ctl->hda->regs->sdesc[i].sts);
694 if ((sts & BIT_V(uint8_t, sdsts_fifoe)) != 0 && (sts & 0x80) == 0) {
695 ddf_msg(LVL_WARN, "sts[%d] = 0x%hhx\n", i, sts);
696 hda_reg8_write(&ctl->hda->regs->sdesc[i].sts,
697 BIT_V(uint8_t, sdsts_fifoe));
698 }
699 }
700}
701
702void hda_ctl_interrupt(hda_ctl_t *ctl)
703{
704 ddf_msg(LVL_DEBUG, "hda_ctl_interrupt");
705 hda_ctl_check_fifo_error(ctl);
706 hda_ctl_process_rirb(ctl);
707}
708
709void hda_ctl_dump_info(hda_ctl_t *ctl)
710{
711 ddf_msg(LVL_DEBUG, "corbwp=%d, corbrp=%d",
712 hda_reg16_read(&ctl->hda->regs->corbwp),
713 hda_reg16_read(&ctl->hda->regs->corbrp));
714 ddf_msg(LVL_DEBUG, "corbctl=0x%x, corbsts=0x%x",
715 hda_reg8_read(&ctl->hda->regs->corbctl),
716 hda_reg8_read(&ctl->hda->regs->corbsts));
717 ddf_msg(LVL_DEBUG, "rirbwp=0x%x, soft-rirbrp=0x%zx",
718 hda_reg16_read(&ctl->hda->regs->rirbwp),
719 ctl->rirb_rp);
720 ddf_msg(LVL_DEBUG, "solrb_wp=0x%zx, solrb_rp=0x%zx",
721 ctl->solrb_wp, ctl->solrb_wp);
722}
723
724/** @}
725 */
Note: See TracBrowser for help on using the repository browser.